In my Debian rootfs I was getting DNS temporary failure when I was doing a apt update. This link fixes the problem ---> https://unix.stackexchange.com/questions/321491/android-chroot-networking-issues
Sunday, 19 May 2019
Monday, 11 March 2019
LCD Parallel Interface parameter calculations
In this post I would like to describe the different LCD parameters and their calculations.
First we understand the LCD display parameters with the following diagram.
In the diagram we have the following terms:
H-Sync: A horizontal synchronize pulse used to synchronize/signal the start of a scan line. Here a scan line means one row/line (of pixels) in the LCD. The signal can be low or a high pulse of a certain duration determined by the setup time (Thsys) and hold time (Thsyh) of this pulse. It is usually mentioned in nano seconds which can also be converted to dotclks which I will come to later.
V-Sync: A veritical synchronize pulse used to synchronize/signal the start of each frame. Here the frame is inclusive of all the vertical and horizontal porches and the H-Sync pulse. The signal can be a low or a high pulse of a certain duration determined by the setup (Tvsys) and hold time (Tvsyh) of this pulse.
HBP and HFP: Horizontal back and front porches. It is used to "eat away" a certain set of pixel clocks before the active line starts and ends. The porch which is before the active line starts is called the back porch and the porch which is after the active line ends is called the front porch. Linux term is left_margin and right_margin for HBP and HFP respectively.
VBP and VFP: Vertical back and from porches. It is used to "eat away" a certain set of lines before after the actual frame starts and ends. Again the porch which is before the active frame is called the back porch and the porch which is after the active frame ends is called the front porch. Linux term is upper_margin and lower_margin for VBP and VFP respectively.
To illustrate the above concepts I will put some of the figures from datasheets
The below example shows the HSYNC in relation to the active pixels, HBP, HFP and also the DOTCLK.
In the diagram above you can see the HSYNC low pulse. The pixel data will keep sending dummy data till the back porch ends with the continuously ticking DOTCLK providing the timing for the HSYNC, HBP, actual pixel data and the HFP. The HBP and HFP period should be a multiple of the DOTCLK period.
Another timing diagram is from the S3C2440 data sheet.
Here we can see the interrupt for the frame sync i.e. VSYNC which is INT_FrSync. This interrupt is useful for the double buffering technique where we can load the image onto an inactive frame buffer between the VSYNCs. When we get the interrupt from the VSYNC we can just change the pointer from the active framebuffer to the back buffer which becomes the active framebuffer. We can start loading the previous framebuffer which becomes inactive.
As seen in the figure the VSYNC and the HSYNC rising edge of the pulse for the start of the frame coincide. In this case the VSYNC and the HSYNC are high pulses. In the figure the VSYNC pulse width is equal to a HSYNC clock period. The polarity of the SYNC pulses can be controlled in the LCDCON5 register. The DOTCLK polarity too can be controlled. As per the figure we can get the follow formula for the Horizontal line time period:
Also for the time for a single frame can be calculated as:
I will explain why porches are needed in the coming sections.
First we understand the LCD display parameters with the following diagram.
In the diagram we have the following terms:
H-Sync: A horizontal synchronize pulse used to synchronize/signal the start of a scan line. Here a scan line means one row/line (of pixels) in the LCD. The signal can be low or a high pulse of a certain duration determined by the setup time (Thsys) and hold time (Thsyh) of this pulse. It is usually mentioned in nano seconds which can also be converted to dotclks which I will come to later.
V-Sync: A veritical synchronize pulse used to synchronize/signal the start of each frame. Here the frame is inclusive of all the vertical and horizontal porches and the H-Sync pulse. The signal can be a low or a high pulse of a certain duration determined by the setup (Tvsys) and hold time (Tvsyh) of this pulse.
HBP and HFP: Horizontal back and front porches. It is used to "eat away" a certain set of pixel clocks before the active line starts and ends. The porch which is before the active line starts is called the back porch and the porch which is after the active line ends is called the front porch. Linux term is left_margin and right_margin for HBP and HFP respectively.
VBP and VFP: Vertical back and from porches. It is used to "eat away" a certain set of lines before after the actual frame starts and ends. Again the porch which is before the active frame is called the back porch and the porch which is after the active frame ends is called the front porch. Linux term is upper_margin and lower_margin for VBP and VFP respectively.
To illustrate the above concepts I will put some of the figures from datasheets
The below example shows the HSYNC in relation to the active pixels, HBP, HFP and also the DOTCLK.
In the diagram above you can see the HSYNC low pulse. The pixel data will keep sending dummy data till the back porch ends with the continuously ticking DOTCLK providing the timing for the HSYNC, HBP, actual pixel data and the HFP. The HBP and HFP period should be a multiple of the DOTCLK period.
Another timing diagram is from the S3C2440 data sheet.
Here we can see the interrupt for the frame sync i.e. VSYNC which is INT_FrSync. This interrupt is useful for the double buffering technique where we can load the image onto an inactive frame buffer between the VSYNCs. When we get the interrupt from the VSYNC we can just change the pointer from the active framebuffer to the back buffer which becomes the active framebuffer. We can start loading the previous framebuffer which becomes inactive.
As seen in the figure the VSYNC and the HSYNC rising edge of the pulse for the start of the frame coincide. In this case the VSYNC and the HSYNC are high pulses. In the figure the VSYNC pulse width is equal to a HSYNC clock period. The polarity of the SYNC pulses can be controlled in the LCDCON5 register. The DOTCLK polarity too can be controlled. As per the figure we can get the follow formula for the Horizontal line time period:
One horizontal line time period = HSYNC width + Horizontal Back porch width + Horizontal data time + Horizontal Front porch width
Also for the time for a single frame can be calculated as:
One frame time period = Vertical Sync pulse width + Vertical back porch + Complete frame time + Vertical back porch
I will explain why porches are needed in the coming sections.
Monday, 4 February 2019
Android Nougat 7.1.1 boot up on Beaglebone Black
Finally got Android Nougat 7.1.1 boot up on my Beaglebone black. I am not sure whether it is a fluke or for real as I have to replicate it again with a rebuild.
I had removed all the different PRODUCT_PROPERTY_OVERRIDES because of one service complaining about another service not being present. One last thing I removed was config.disable_noncore=true. Now I re-enabled the same and built the whole thing up. I will update the results soon.
*Update*: Tried adding config.disable_noncore and it starts crashing. Did a make clean and rebuilt by removing config.disable_noncore and it started working.
Also I bought a new set of microSD cards which are class 10 and is much faster than the previous crappy microSD cards. Let me see if they made a difference.
*Update*: Yes they make a difference. They are faster to write and it is faster for the overall system too.
There is still a crash which I saw in the first boot which is IpManager.eth0 which was plaguing before. Leaving the system just like that manages to start the system even though there is a single set of kills of audioserver, cameraserver, media, netd but it recovers. This problem I think I will have to try fixing it. Doing a simple cursory search shows a Linaro chat log saying it is some subtle timing bug introduced by the printing but I am not very sure about this.
A 'service list' commands gives the following services:
In the mean time a screenshot to celebrate.
I had removed all the different PRODUCT_PROPERTY_OVERRIDES because of one service complaining about another service not being present. One last thing I removed was config.disable_noncore=true. Now I re-enabled the same and built the whole thing up. I will update the results soon.
*Update*: Tried adding config.disable_noncore and it starts crashing. Did a make clean and rebuilt by removing config.disable_noncore and it started working.
Also I bought a new set of microSD cards which are class 10 and is much faster than the previous crappy microSD cards. Let me see if they made a difference.
*Update*: Yes they make a difference. They are faster to write and it is faster for the overall system too.
There is still a crash which I saw in the first boot which is IpManager.eth0 which was plaguing before. Leaving the system just like that manages to start the system even though there is a single set of kills of audioserver, cameraserver, media, netd but it recovers. This problem I think I will have to try fixing it. Doing a simple cursory search shows a Linaro chat log saying it is some subtle timing bug introduced by the printing but I am not very sure about this.
A 'service list' commands gives the following services:
beagleboneblack:/ # service list Found 112 services: 0 carrier_config: [com.android.internal.telephony.ICarrierConfigLoader] 1 phone: [com.android.internal.telephony.ITelephony] 2 isms: [com.android.internal.telephony.ISms] 3 iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo] 4 simphonebook: [com.android.internal.telephony.IIccPhoneBook] 5 telecom: [com.android.internal.telecom.ITelecomService] 6 isub: [com.android.internal.telephony.ISub] 7 contexthub_service: [android.hardware.location.IContextHubService] 8 dns_listener: [android.net.metrics.IDnsEventListener] 9 connmetrics: [android.net.IIpConnectivityMetrics] 10 connectivity_metrics_logger: [android.net.IConnectivityMetricsLogger] 11 imms: [com.android.internal.telephony.IMms] 12 media_projection: [android.media.projection.IMediaProjectionManager] 13 launcherapps: [android.content.pm.ILauncherApps] 14 shortcut: [android.content.pm.IShortcutService] 15 trust: [android.app.trust.ITrustManager] 16 media_router: [android.media.IMediaRouterService] 17 media_session: [android.media.session.ISessionManager] 18 restrictions: [android.content.IRestrictionsManager] 19 graphicsstats: [android.view.IGraphicsStats] 20 assetatlas: [android.view.IAssetAtlas] 21 dreams: [android.service.dreams.IDreamManager] 22 commontime_management: [] 23 network_time_update_service: [] 24 samplingprofiler: [] 25 diskstats: [] 26 appwidget: [com.android.internal.appwidget.IAppWidgetService] 27 soundtrigger: [com.android.internal.app.ISoundTriggerService] 28 jobscheduler: [android.app.job.IJobScheduler] 29 hardware_properties: [android.os.IHardwarePropertiesManager] 30 serial: [android.hardware.ISerialManager] 31 usb: [android.hardware.usb.IUsbManager] 32 DockObserver: [] 33 audio: [android.media.IAudioService] 34 wallpaper: [android.app.IWallpaperManager] 35 dropbox: [com.android.internal.os.IDropBoxManagerService] 36 search: [android.app.ISearchManager] 37 country_detector: [android.location.ICountryDetector] 38 location: [android.location.ILocationManager] 39 devicestoragemonitor: [] 40 notification: [android.app.INotificationManager] 41 recovery: [android.os.IRecoverySystem] 42 updatelock: [android.os.IUpdateLock] 43 servicediscovery: [android.net.nsd.INsdManager] 44 connectivity: [android.net.IConnectivityManager] 45 ethernet: [android.net.IEthernetManager] 46 rttmanager: [android.net.wifi.IRttManager] 47 wifiscanner: [android.net.wifi.IWifiScanner] 48 wifi: [android.net.wifi.IWifiManager] 49 wifip2p: [android.net.wifi.p2p.IWifiP2pManager] 50 netpolicy: [android.net.INetworkPolicyManager] 51 netstats: [android.net.INetworkStatsService] 52 network_score: [android.net.INetworkScoreService] 53 textservices: [com.android.internal.textservice.ITextServicesManager] 54 network_management: [android.os.INetworkManagementService] 55 clipboard: [android.content.IClipboard] 56 statusbar: [com.android.internal.statusbar.IStatusBarService] 57 device_policy: [android.app.admin.IDevicePolicyManager] 58 deviceidle: [android.os.IDeviceIdleController] 59 lock_settings: [com.android.internal.widget.ILockSettings] 60 uimode: [android.app.IUiModeManager] 61 mount: [IMountService] 62 accessibility: [android.view.accessibility.IAccessibilityManager] 63 input_method: [com.android.internal.view.IInputMethodManager] 64 pinner: [] 65 vrmanager: [android.service.vr.IVrManager] 66 input: [android.hardware.input.IInputManager] 67 window: [android.view.IWindowManager] 68 alarm: [android.app.IAlarmManager] 69 consumer_ir: [android.hardware.IConsumerIrService] 70 vibrator: [android.os.IVibratorService] 71 content: [android.content.IContentService] 72 account: [android.accounts.IAccountManager] 73 media.camera.proxy: [android.hardware.ICameraServiceProxy] 74 telephony.registry: [com.android.internal.telephony.ITelephonyRegistry] 75 scheduling_policy: [android.os.ISchedulingPolicyService] 76 webviewupdate: [android.webkit.IWebViewUpdateService] 77 usagestats: [android.app.usage.IUsageStatsManager] 78 battery: [] 79 sensorservice: [android.gui.SensorServer] 80 processinfo: [android.os.IProcessInfoService] 81 permission: [android.os.IPermissionController] 82 cpuinfo: [] 83 dbinfo: [] 84 gfxinfo: [] 85 meminfo: [] 86 procstats: [com.android.internal.app.procstats.IProcessStats] 87 activity: [android.app.IActivityManager] 88 user: [android.os.IUserManager] 89 otadexopt: [android.content.pm.IOtaDexopt] 90 package: [android.content.pm.IPackageManager] 91 display: [android.hardware.display.IDisplayManager] 92 power: [android.os.IPowerManager] 93 appops: [com.android.internal.app.IAppOpsService] 94 batterystats: [com.android.internal.app.IBatteryStats] 95 netd: [android.net.INetd] 96 media.resource_manager: [android.media.IResourceManagerService] 97 media.player: [android.media.IMediaPlayerService] 98 media.drm: [android.media.IMediaDrmService] 99 media.sound_trigger_hw: [android.hardware.ISoundTriggerHwService] 100 media.radio: [android.hardware.IRadioService] 101 media.audio_policy: [android.media.IAudioPolicyService] 102 media.extractor: [android.media.IMediaExtractorService] 103 media.audio_flinger: [android.media.IAudioFlinger] 104 drm.drmManager: [drm.IDrmManagerService] 105 media.camera: [android.hardware.ICameraService] 106 media.codec: [android.media.IMediaCodecService] 107 android.service.gatekeeper.IGateKeeperService: [android.service.gatekeeper.IGateKeeperService] 108 android.security.keystore: [android.security.IKeystoreService] 109 gpu: [android.ui.IGpuService] 110 SurfaceFlinger: [android.ui.ISurfaceComposer] 111 batteryproperties: [android.os.IBatteryPropertiesRegistrar]
In the mean time a screenshot to celebrate.
Thursday, 31 January 2019
Binder driver protocol does not match user space protocol
After updating my Kernel 4.4 branch and also Android repo syncing of Nougat I started getting Binder driver protocol does not match user space protocol.
Log of my work follows:
Next step is to fix the hwcomposer not found issue. Let us see how that goes.
Log of my work follows:
- Updating kernel headers in bionic is the first step which was highlighted in my previous post
- Next I started snooping around and found that frameworks/libs/binder/ProcessState.cpp checks the version and then fails
- I wrote a simple C program to check what version the binder driver and the ioctl responds with Version 8
- Next I check the kernel headers and find that there is a version switch when BINDER_IPC_32BIT is defined or something else possibly BINDER_IPC_64BIT Ref: https://elixir.bootlin.com/linux/v4.4/source/include/uapi/linux/android/binder.h#L43 and https://elixir.bootlin.com/linux/v4.4/source/include/uapi/linux/android/binder.h#L94
- Changed it in the source external/kernel-headers/original/....../binder.h and commented out the BINDER_IPC_32BIT and kept only the 64 bit. This is because the kernel has moved on to 64 bit and there is no support for 32 bit. Due to this the KConfig variable is removed. I have still experiment by manually modifying the .config variable
- Ran tools/update_all.py and finally rebuilt the whole AOSP.
Next step is to fix the hwcomposer not found issue. Let us see how that goes.
Wednesday, 30 January 2019
Updating kernel headers in the AOSP
I updated Linux Kernel 4.4 to the latest revision. I am now trying with AOSP kernel rather than the linux stable kernel.
To update the kernel headers I follow this excellent guide:
https://android.googlesource.com/platform/bionic/+/master/libc/kernel/README.TXT
I am now fixing the errors after the update. I will be updating my progress soon.
To update the kernel headers I follow this excellent guide:
https://android.googlesource.com/platform/bionic/+/master/libc/kernel/README.TXT
I am now fixing the errors after the update. I will be updating my progress soon.
Tuesday, 29 January 2019
Timed out waiting for device dev-ttyO0.device
While booting my Beaglebone black on debian Rootfs I stumbled upon the following problem:
"Timed out waiting for device dev-ttyO0.device"
To fix this enable CONFIG_FHANDLE in the kernel.
Credits: https://medium.com/@madhav2code/timed-out-waiting-for-device-dev-ttys0-device-827391917c5d
"Timed out waiting for device dev-ttyO0.device"
To fix this enable CONFIG_FHANDLE in the kernel.
Credits: https://medium.com/@madhav2code/timed-out-waiting-for-device-dev-ttys0-device-827391917c5d
Thursday, 14 June 2018
Flex crash while building AOSP
I encountered a Flex crash while building AOSP. The crash as follows:
[ 1% 618/35534] Lex: aidl <= system/tools/aidl/aidl_language_l.ll
FAILED: /bin/bash -c "prebuilts/misc/linux-x86/flex/flex-2.5.39 -oout/host/linux-x86/obj/STATIC_LIBRARIES/libaidl-common_intermediates/aidl_language_l.cpp system/tools/aidl/aidl_language_l.ll"
flex-2.5.39: loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed.
Aborted (core dumped)
Turns out this is because LC_ALL is set to nothing in my machine in Ubuntu 18.04. You can see this variable by typing "locale" in the command line. To fix this just do a:
export LC_ALL=C
The solution reference is here: https://stackoverflow.com/questions/49301627/android-7-1-2-armv7
[ 1% 618/35534] Lex: aidl <= system/tools/aidl/aidl_language_l.ll
FAILED: /bin/bash -c "prebuilts/misc/linux-x86/flex/flex-2.5.39 -oout/host/linux-x86/obj/STATIC_LIBRARIES/libaidl-common_intermediates/aidl_language_l.cpp system/tools/aidl/aidl_language_l.ll"
flex-2.5.39: loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed.
Aborted (core dumped)
Turns out this is because LC_ALL is set to nothing in my machine in Ubuntu 18.04. You can see this variable by typing "locale" in the command line. To fix this just do a:
export LC_ALL=C
The solution reference is here: https://stackoverflow.com/questions/49301627/android-7-1-2-armv7
Sunday, 29 April 2018
Playing a sound alert
I found an interesting way to generate sound alerts after a task gets finished. You can install sox with which you can generate sounds. A simple command such as play -n synth 0.2 sin 440 can help generate a audio beep which can indicate a build done or some other alert.
In the above command -n specifies a null file i.e. do not generate a file, synth 0.2 tells how many seconds and sin 400 tells a sine way of 440 Hz.
In the above command -n specifies a null file i.e. do not generate a file, synth 0.2 tells how many seconds and sin 400 tells a sine way of 440 Hz.
AM33xx sysboot settings
AM33xx document is not very clear on the sysboot settings. Recently when working on it I had some trouble finding out where in the document the SYSBOOT[15:0] pins correspond to the LCD_DATA[51:0] inputs. It is in page 5033 of spruh73p documentation in chapter 26.1.6 Booting, 26.1.6.2 Device list and sub chapter 26.1.6.2.1 SYSBOOT CONFIGURATION.
To quote:
"SYSBOOT[15:0] terminals are respectively LCD_DATA[15:0] inputs, latched on the rising edge of PWRONRSTn."
To quote:
"SYSBOOT[15:0] terminals are respectively LCD_DATA[15:0] inputs, latched on the rising edge of PWRONRSTn."
Saturday, 14 April 2018
Hitting partition limit in Beaglebone black Linux kernel
At work I was recently hit with the partition limit of 8 partitions. It was quite strange and debugging for hours with the kernel dmesg showing only 8 partitions being detected but lsblk and fdisk showing all the remaining partitions I was puzzled. Due the kernel not detecting more than 8 partitions udev would not create the device nodes for the undetected partitions. Narrowing down the problem to the kernel and wondering if it is a bug I did a google search for partition limit in beaglebone. It finally revealed the kernel config to be CONFIG_MMC_BLOCK_MINORS=8 which was limiting the partitions.
Reference to the original thread: https://groups.google.com/d/msg/beagleboard/IJpym7xOFBA/Cb7JQNS_6KcJ
Thanks to Robert C Nelson for helping with the problem and Ankur Tank for posting the problem in Google groups and Superuser.
Reference to the original thread: https://groups.google.com/d/msg/beagleboard/IJpym7xOFBA/Cb7JQNS_6KcJ
Thanks to Robert C Nelson for helping with the problem and Ankur Tank for posting the problem in Google groups and Superuser.
Friday, 16 March 2018
Solving "No Partitions Present" When Installing Xubuntu/Kubuntu/Ubuntu
When I was installing Xubuntu using DVD or USB stick I was faced with the problem of finding no partitions showing in the partitioning screen. I only see a complete /dev/sdX with no partitions present.
After installing 14.04, 16.10 and 17.10 and spending a lot of time very late at night I finally found after researching that the disk has RAID metadata which seems to confuse the partitioning software. To fix this I did the following:
Here -r means raid and -E erase metadata. In combination it will remove the old metadata. Do this in the "Try Xubuntu" by opening a console. If the package is not found install using apt.
I had also tried GPT fixing before using FixParts but the program said my partitions were okay. So to make you aware it would not be the GPT but the software RAID that might be causing the problem.
References:
After installing 14.04, 16.10 and 17.10 and spending a lot of time very late at night I finally found after researching that the disk has RAID metadata which seems to confuse the partitioning software. To fix this I did the following:
sudo dmraid -rE /dev/sdX
Here -r means raid and -E erase metadata. In combination it will remove the old metadata. Do this in the "Try Xubuntu" by opening a console. If the package is not found install using apt.
I had also tried GPT fixing before using FixParts but the program said my partitions were okay. So to make you aware it would not be the GPT but the software RAID that might be causing the problem.
References:
Sunday, 11 March 2018
Using serial device file without sudo or root permissions
When we use the PL2303 or any other connector we get the serial device file as /dev/ttyUSBx where x=0,1,2,3... . If we see the permissions of this file we find that the owner is root and the group is dialout. Hence using a serial console program with normal user permissions will not work as I would not have the appropriate permissions. To fix this first add the user to the dialout group.
Next we modify the udev rules file with the appropriate rules as follows:
Replace "xxxx" and "yyyy" with your USB vendor ID and USB product ID respectively.
I create a file named <somenum>-serialadapter.rules in /etc/udev/rules.d/
Next to trigger the above rules we do the following:
Now we can use screen or minicom on the device file without using root or sudo.
Next we modify the udev rules file with the appropriate rules as follows:
ATTRS{idVendor}=="xxxx",ATTRS{idProduct}=="yyyy", MODE="0660",GROUP="plugdev"
Replace "xxxx" and "yyyy" with your USB vendor ID and USB product ID respectively.
I create a file named <somenum>-serialadapter.rules in /etc/udev/rules.d/
Next to trigger the above rules we do the following:
sudo udevadm control --reload-rules && sudo udevadm trigger
Now we can use screen or minicom on the device file without using root or sudo.
Thursday, 25 January 2018
Merging Android patches into Linux kernel
I am trying to port Android to the Beaglebone black and do a basic kernel boot. This is the step by step log of my journey.
First I clone the mainline kernel and boot up my BBB. I use the omap2plus_defconfig and am335x-boneblack.dtb file to boot-up the BBB. This will act as my reference kernel.
Next I clone the Android kernel as follows:
Next we check the branches of the Android kernel. We do a git branch -a. The partial output is as follows:
I have decided to use the 4.14 kernel. So I decide to checkout the 4.14 in both the Reference kernel and Android kernel.
In my Android tree I do a:
Git log generally shows:
"Merge 4.14.14 into android-4.14"
In the Linux kernel we do the same:
Git log generally shows:
"Linux 4.14"
Next we start the merging process.
We go to the Android kernel directory and check for the point where Linux 4.14 LTS was used to add the Android patches on top. For this we do the following:
We get the following output:
I find Linux 4.14 with the commit hash of "bebc6082da0a9f5d47a1ea2edc099bf671058bd4" which is the same hash which I see in the reference kernel when I do a git log.
Now I extract all the patches from 4.14 Linux commit hash to the HEAD which is all the Android patches added to the 4.14 LTS version. I do the following:
Next we first check and then apply the 4.14_android.patch to the Reference Linux kernel which we have checked out at tag 4.14 and branched it. I 'cd' to the reference kernel directory and do the following:
First I check the patch application to see if there are any errors and then apply without the check.
Next I build the kernel. Here I merge the .config files of the board i.e. omap2plus_defconfig, android-base.config and android-recommended.config. I issue the following command:
A .config file gets generated which I will use to build, flash and verify if the build is working fine using my Debian rootfs. Please note that there might be an issue with the systemd trying to bring up ttyO0 which I am trying to get it resolved. This works fine in the Reference kernel 4.14 and also after merging with just the omapplus2_defconfig but not after the merging of .config files of android and omapplus2.
Please note that the terminal and dns might not work. The solution is as follows:
For the terminal login to work make sure CONFIG_VT=y and CONFIG_FHANDLE=y.
For the DNS to work we need to disable PARANOID_NETWORKING. If you still want to enable PARANOID_NETWORKING then you need to add the following groups with their GIDs:
AID_INET: 3003
AID_NET_RAW: 3004
AID_NET_ADMIN: 3005
My sample addition of users to groups is as follows:
Even though some of the network utilities work I was unable to make apt resolve the addresses. I still need to tinker with the options to make it work. I will update it here when I am able to get it working.
First I clone the mainline kernel and boot up my BBB. I use the omap2plus_defconfig and am335x-boneblack.dtb file to boot-up the BBB. This will act as my reference kernel.
Next I clone the Android kernel as follows:
git clone https://android.googlesource.com/kernel/common
Next we find match the kernel version numbers. So in my reference kernel I check the tags of the kernel version number. My partial output is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | v4.13 v4.13-rc1 v4.13-rc2 v4.13-rc3 v4.13-rc4 v4.13-rc5 v4.13-rc6 v4.13-rc7 v4.14 v4.14-rc1 v4.14-rc2 v4.14-rc3 v4.14-rc4 v4.14-rc5 v4.14-rc6 v4.14-rc7 v4.14-rc8 v4.15-rc1 |
Next we check the branches of the Android kernel. We do a git branch -a. The partial output is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 | remotes/origin/android-3.18-n-release remotes/origin/android-3.18-o-mr1 remotes/origin/android-3.18-o-release remotes/origin/android-4.14 remotes/origin/android-4.4 remotes/origin/android-4.4-eas-test remotes/origin/android-4.4-llvm remotes/origin/android-4.4-n remotes/origin/android-4.4-n-release remotes/origin/android-4.4-o remotes/origin/android-4.4-o-mr1 remotes/origin/android-4.4-o-release |
I have decided to use the 4.14 kernel. So I decide to checkout the 4.14 in both the Reference kernel and Android kernel.
In my Android tree I do a:
1 | git checkout remotes/origin/android-4.14 -b android_4.14_linux_merge |
Git log generally shows:
"Merge 4.14.14 into android-4.14"
In the Linux kernel we do the same:
1 | git checkout v4.14 -b linux_4.14_android_merge |
Git log generally shows:
"Linux 4.14"
Next we start the merging process.
We go to the Android kernel directory and check for the point where Linux 4.14 LTS was used to add the Android patches on top. For this we do the following:
git log --pretty=oneline --grep="Linux 4.14"
We get the following output:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 9b68347c3554e886487ea5587cde21926d950f15 (HEAD -> android_4.14_linux_merge, origin/android-4.14) Merge 4.14.14 into android-4.14 9c0bf9847171edd597a13adf3ddc879e96d947cd (origin/upstream-linux-4.14.y) Linux 4.14.14 918914133ea13a07ec7967b25f0992c1f8928411 Merge 4.14.13 into android-4.14 b8447222eb207d5a5ec20a0f357065963dabdcd0 Linux 4.14.13 81e7d4589439a5b5dd07b7ecb7b02dbea7f6f795 Merge 4.14.12 into android-4.14 8d577afdee3540808302d9dc7a0a7be96c91178f Linux 4.14.12 51caa5cc8092b11fd91a7ffc12428bff47ddf518 Merge 4.14.11 into android-4.14 7af3494ec5325187effc30bef12ae72318cb2108 Merge 4.14.10 into android-4.14 0cf36be1cdf63598e98f094d4fb5e65dab164d14 Merge 4.14.9 into android-4.14 7237d3f322a7b005f751eb0e8da6e766ae6d9dca Merge 4.14.8 into android-4.14 5adbbb16a574d794c3b1573b8bcc0f51b3035985 Merge 4.14.7 into android-4.14 20f3b53781e9102b365f66cfa883aee95e932bb3 Merge 4.14.6 into android-4.14 0730eb4486b992c6a6193b48d54ffb463e4cec73 Merge 4.14.5 into android-4.14 0730eb4486b992c6a6193b48d54ffb463e4cec73 Merge 4.14.5 into android-4.14 c5c36272cda5e0fddadd1cff144d436514e509f2 Merge 4.14.4 into android-4.14 50cb0d5ca6df48129265cf7bde4e738fe509050c Merge 4.14.3 into android-4.14 fbbc906cb44d660eee3ce8c6c30eeccc79ecb144 Merge 4.14.2 into android-4.14 dc6bfa18652919ae193a3bcd05c6fcc49327bdd0 Merge 4.14.1 into android-4.14 0d59679df5b53755c00ea0292df696f97bfc950d Linux 4.14.11 b8ce8232fcc37fe7a97db79ea0a5f32098c25e72 Linux 4.14.10 dad5c1402c570cd07a80113784bc20a7f930c8ae Linux 4.14.9 7b3775017f4e6b87dfd2c7f63d1eaf057948f31d Linux 4.14.8 3afae8437c3cbc22966762e80e81818f5a90eb06 Linux 4.14.7 5fd159e1ee6a87a72626139813034f24f047d0e6 Linux 4.14.6 64138f0adb25ca8f34baa57af33260b05efe2874 Linux 4.14.5 51a2a68fde2035887c0d74aee1c9569c691dfd61 Linux 4.14.4 191314edb326764c4481b09ccf7d00159abe4679 Linux 4.14.3 f9f0b03dedc19a6363a305d119efcb48667a3027 Linux 4.14.2 780a781dd6f1af9dfac15b8eeba1cb678c9fc380 Linux 4.14.1 bebc6082da0a9f5d47a1ea2edc099bf671058bd4 Linux 4.14 39dae59d66acd86d1de24294bd2f343fd5e7a625 Linux 4.14-rc8 0b07194bb55ed836c2cc7c22e866b87a14681984 Linux 4.14-rc7 bb176f67090ca54869fc1262c913aa69d2ede070 Linux 4.14-rc6 33d930e59a98fa10a0db9f56c7fa2f21a4aef9b9 Linux 4.14-rc5 8a5776a5f49812d29fe4b2d0a2d71675c3facf3f Linux 4.14-rc4 9e66317d3c92ddaab330c125dfe9d06eee268aff Linux 4.14-rc3 e19b205be43d11bff638cad4487008c48d21c103 Linux 4.14-rc2 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e Linux 4.14-rc1 f9773b22a27a4234f436c9570afd62d905e00a13 Merge tag 'nfs-rdma-for-4.14-1' of git://git.linux-nfs.org/projects/anna/linux-nfs into linux-next 2b76da95638010a70435f8455913133acc26e93f Merge branch 'nvme-4.14' of git://git.infradead.org/nvme into fo |
I find Linux 4.14 with the commit hash of "bebc6082da0a9f5d47a1ea2edc099bf671058bd4" which is the same hash which I see in the reference kernel when I do a git log.
Now I extract all the patches from 4.14 Linux commit hash to the HEAD which is all the Android patches added to the 4.14 LTS version. I do the following:
git diff bebc608 HEAD > 4.14_android.patch
Next we first check and then apply the 4.14_android.patch to the Reference Linux kernel which we have checked out at tag 4.14 and branched it. I 'cd' to the reference kernel directory and do the following:
1 2 | git apply --check ../4.14_android.patch git apply ../4.14_android.patch |
First I check the patch application to see if there are any errors and then apply without the check.
Next I build the kernel. Here I merge the .config files of the board i.e. omap2plus_defconfig, android-base.config and android-recommended.config. I issue the following command:
LOADADDR=0x80008000 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- scripts/kconfig/merge_config.sh arch/arm/configs/omap2plus_defconfig kernel/configs/android-base.config kernel/configs/android-recommended.config
A .config file gets generated which I will use to build, flash and verify if the build is working fine using my Debian rootfs. Please note that there might be an issue with the systemd trying to bring up ttyO0 which I am trying to get it resolved. This works fine in the Reference kernel 4.14 and also after merging with just the omapplus2_defconfig but not after the merging of .config files of android and omapplus2.
Please note that the terminal and dns might not work. The solution is as follows:
For the terminal login to work make sure CONFIG_VT=y and CONFIG_FHANDLE=y.
For the DNS to work we need to disable PARANOID_NETWORKING. If you still want to enable PARANOID_NETWORKING then you need to add the following groups with their GIDs:
AID_INET: 3003
AID_NET_RAW: 3004
AID_NET_ADMIN: 3005
My sample addition of users to groups is as follows:
AID_INET:x:3003:debian,root,avahi,avahi-autoipd,_apt,systemd-timesync,systemd-resolve,systemd-bus-proxy AID_NET_RAW:x:3004:debian,root,avahi,avahi-autoipd,_apt,systemd-timesync,systemd-resolve,systemd-bus-proxy AID_NET_ADMIN:x:3005:debian,root,avahi,avahi-autoipd,_apt,systemd-bus-proxy,systemd-timesync,systemd-resolve
Even though some of the network utilities work I was unable to make apt resolve the addresses. I still need to tinker with the options to make it work. I will update it here when I am able to get it working.
Tuesday, 23 January 2018
Android AOSP Nougat Build and Jack "Out of Memory" issue resolution.
I had downloaded Android Nougat before and had failed miserably with Jack. It used to always give me a "Out of memory" error. I have an Intel Quad Core Q8200 2.33GHz laptop with 4GB of RAM.
Looking around I found a post by Chris Simmonds in his blog which said which says to increase the memor
Looking around I found a post by Chris Simmonds in his blog which said which says to increase the memor
y using the JACK_SERVER_VM_ARGUMENTS environment variable. I set the following value in my ~/.jack_settings i.e. max memory to 3GB:1 | JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx3g" |
While
compilation I still had problems with JACK Server having communication
problems. I further reduced the JACK compile jobs to by setting the
SERVER_NB_COMPILE=1 in ~/.jack_settings.Please see reference 3 where the Google documentation for JACK is updated and it details on different parameters JACK.
I am not sure whether the problem was resolved by installing ibcurl4-openssl-dev and nss-updatedb packages but it is worth to give a try.
After this I was able to completely build Nougat and boot it up using my emulator. The final aim is to understand how to boot Nougat on the Beaglebone.
Reference:Chris simmonds post: http://www.2net.co.uk/blog/jack-server.htmlGoogle groups post: https://groups.google.com/forum/#!topic/android-building/8SQ0-4zZDo8Google Gerrit Jack Documentation change: https://android-review.googlesource.com/c/platform/prebuilts/sdk/+/233481
Tuesday, 16 January 2018
Creating a bootscript file for u-boot
I have created a boot script file to boot my Beaglebone via tftp. I did not want to change the default boot configuration in the headers as it would add changes to my u-boot code which would deviate from the mainline.
First we create a file called boot.cmd. I have the following in my boot.cmd file which can be reused.
We change this to boot.scr file by doing the following:
We keep this boot.scr in the first partition. We reset/reboot/boot the board and then we do the following:
Basically the above would load the boot.scr file in 0x80000000 location and run the script from that location by doing a run <memory_address>.
I will improve on this script a little bit and will keep updating this blog post.
First we create a file called boot.cmd. I have the following in my boot.cmd file which can be reused.
1 2 3 4 5 6 7 8 9 10 | setenv bootargs console=${console} root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait
setenv fdtaddr 0x8C008000
setenv loadaddr 0x80008000
run findfdt
setenv tftp_fdt tftp ${fdtaddr} ${fdtfile}
setenv tftp_uimage tftp ${loadaddr} uImage
setenv sd_fdt fatload mmc 0:1 ${fdtaddr} ${fdtfile}
setenv sd_uimage fatload mmc 0:1 ${loadaddr} uImage
setenv tftpboot 'run tftp_fdt; run tftp_uimage; bootm ${loadaddr} - ${fdtaddr}'
setenv sdboot 'run sd_fdt; run sd_uimage; bootm ${loadaddr} - ${fdtaddr}'
|
We change this to boot.scr file by doing the following:
1 | mkimage -C none -A arm -T script -d boot.cmd boot.scr |
We keep this boot.scr in the first partition. We reset/reboot/boot the board and then we do the following:
1 2 3 4 5 | fatload mmc 0:1 0x80000000 boot.scr source 0x80000000 setenv serverip <yourtftp ip address> setenv ipaddr <yourbeagleboneip> run tftpboot |
Basically the above would load the boot.scr file in 0x80000000 location and run the script from that location by doing a run <memory_address>.
I will improve on this script a little bit and will keep updating this blog post.
Wednesday, 3 January 2018
Beaglebone UART connection using PL2303 USB to UART adapter
To connect to the Beaglebone UART for console messages I connect to my PC with a PL2303 USB to UART adapter.
The product page is present here: https://www.adafruit.com/product/954
We have the wire color coding and pin-out to the Beaglebone's J1 header6 (6 pin header) as follows:
Red: +5V (DANGER: Do not connect to any of the UART headers. Please keep it unused for UART. You may use it for something else but please read the specifications before doing it)
Black: Gnd (Pin 1 which is marked with white dot)
Green: Tx from USB port to Rx of BeagleBone UART (Pin 4. Net Name: B_UART0_RX)
White: Rx into USB port from Tx of BeagleBone UART (Pin 5. Net Name: B_UART0_TX)
A reference image to easily verify:
After connection you can verify the console messages using a program like screen with a configuration 115200n81.
The product page is present here: https://www.adafruit.com/product/954
We have the wire color coding and pin-out to the Beaglebone's J1 header6 (6 pin header) as follows:
Red: +5V (DANGER: Do not connect to any of the UART headers. Please keep it unused for UART. You may use it for something else but please read the specifications before doing it)
Black: Gnd (Pin 1 which is marked with white dot)
Green: Tx from USB port to Rx of BeagleBone UART (Pin 4. Net Name: B_UART0_RX)
White: Rx into USB port from Tx of BeagleBone UART (Pin 5. Net Name: B_UART0_TX)
A reference image to easily verify:
After connection you can verify the console messages using a program like screen with a configuration 115200n81.
Saturday, 30 December 2017
Android Studio Options not visible
I was trying to learn some Android Native stuff and after installation of Android Studio and starting up I could not see "Include C++ support" and "Include Kotlin support" in the "Create New Project" wizard in my Ubuntu 17.10. Also the "Welcome to Android Studio" windows was very enlarged. Struggling I finally found the root cause of the problem. Generally I increase my Xubuntu Windows appearance fonts as I am comfortable with large fonts. This large font causes problems with the Android Studio layout manager and some of the Window elements disappears. I reduced the size of the font to 12 which was 18 before and I could start seeing the different options once again. For reference the font settings is present in "Settings Manager --> Appearance --> Fonts Tab".
Hope this helps some of the people facing this problem.
Hope this helps some of the people facing this problem.
Tuesday, 19 December 2017
Create a rootfs with Debian debootstrap
I wanted to create a custom rootfs instead of using the RCN debian rootfs image. Following are the steps:
We create the first stage of rootfs as follows:
This would start downloading the initial bootstrap packages for a successful chroot.
Next I do the following to start off the second stage
Next I modify the sources.list file as per my Debian distro from https://debgen.simplylinux.ch/
I do the following to update and configure packages:
Next I run passwd to change my root password.
I then do the following to move the files to the target partition from which Linux uses as its root file system
Please note that I use the "p" flag to preserve the permissions.
This concludes the basic rootfs. There are still things missing like networking which I will experiment and further add to this post.
For network connection setup please edit the interfaces file as provided in the Debian network configuration wiki.
Sample of my network configuration file:
I had to install ifupdown2 packages so that there are no errors in the systemd scripts. It uses a ifquery which was not present in the rootfs as the package it was present i.e. ifupdown2 was missing.
Also I installed the udhcpd package for DHCP. I am not sure how much it helps but if there is a problem with the interface getting an IP via DHCP this might help.
Apart from that I created a normal user with sudo access. Creation is as simple as "adduser <username>" and adding the user to sudo group as "adduser <username> sudo"
When chrooting to the directory it might start complaining about pts. We can mount the pts psuedo filesystem as follows:
For further references we can see the excellent debian wiki at https://wiki.debian.org/chroot
We will have to install the modules, firmware and headers installation to the rootfs. We can create a temporary directory to verify if all is ok and then copy it to our root filesystem.
We do the modules,firmware and headers installation as follows:
Next we copy the contents of firmware_path to <mountdir>/lib/firmware, modules_path to <mountdir>/lib/modules and headers_path to <mountdir>/usr/
We create the first stage of rootfs as follows:
sudo debootstrap --arch=armhf --foreign stretch <target_dir>
This would start downloading the initial bootstrap packages for a successful chroot.
Next I do the following to start off the second stage
1 2 3 | sudo chroot <target_dir> export LANG=C /debootstrap/debootstrap --second-stage |
Next I modify the sources.list file as per my Debian distro from https://debgen.simplylinux.ch/
I do the following to update and configure packages:
1 2 3 4 | apt update apt-get install locales dialog dpkg-reconfigure locales apt install openssh-server ntpdate |
Next I run passwd to change my root password.
I then do the following to move the files to the target partition from which Linux uses as its root file system
1 2 | cd target_dir sudo cp -rpv . /mnt/devmnt |
Please note that I use the "p" flag to preserve the permissions.
This concludes the basic rootfs. There are still things missing like networking which I will experiment and further add to this post.
For network connection setup please edit the interfaces file as provided in the Debian network configuration wiki.
Sample of my network configuration file:
1 2 3 4 5 6 7 | # interfaces(5) file used by ifup(8) and ifdown(8) # Include files from /etc/network/interfaces.d: source-directory /etc/network/interfaces.d auto eth0 allow-hotplug eth0 iface eth0 inet dhcp |
I had to install ifupdown2 packages so that there are no errors in the systemd scripts. It uses a ifquery which was not present in the rootfs as the package it was present i.e. ifupdown2 was missing.
Also I installed the udhcpd package for DHCP. I am not sure how much it helps but if there is a problem with the interface getting an IP via DHCP this might help.
Apart from that I created a normal user with sudo access. Creation is as simple as "adduser <username>" and adding the user to sudo group as "adduser <username> sudo"
When chrooting to the directory it might start complaining about pts. We can mount the pts psuedo filesystem as follows:
1 | mount --bind /dev/pts <rootfs directory>/dev/pts |
For further references we can see the excellent debian wiki at https://wiki.debian.org/chroot
We will have to install the modules, firmware and headers installation to the rootfs. We can create a temporary directory to verify if all is ok and then copy it to our root filesystem.
We do the modules,firmware and headers installation as follows:
1 2 3 | LOADADDR=0x80008000 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j10 firmware_install INSTALL_FW_PATH=../firmware_path/ LOADADDR=0x80008000 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j10 modules_install INSTALL_MOD_PATH=../modules_path/ LOADADDR=0x80008000 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j10 headers_install INSTALL_HDR_PATH=../headers_path/ |
Next we copy the contents of firmware_path to <mountdir>/lib/firmware, modules_path to <mountdir>/lib/modules and headers_path to <mountdir>/usr/
Friday, 8 December 2017
BeagleBone Black Linux setup for development
After my wandboard starting behaving weirdly due to some RAM problems I decided to experiment Android and Linux on my BeagleBone Black.
BeagleBone Black is a really nice and capable SBC. I will document my Linux experiments similar to Wandboard here. We will first start with the Linux setup and installation.
I am going to the use Robert C Nelson (hereafter RCN) trees for building my kernel.
We have the BB Kernel tree here: https://github.com/RobertCNelson/bb-kernel.git
We do a git clone and git checkout 4.14-rc8-bone3. We can just call the build_kernel.sh which will build the kernel automatically. We can reuse the .config for our customization.
We can also use the bleeding edge tree: https://github.com/beagleboard/linux.git
In the above tree we can build the image manually. The baremetal toolchains arm-none-eabi- from the Ubuntu repository and the arm-eabi- from the ARM/Linaro toolchain will cause errors in the build. After observing the BB Kernel tree build messages I see that the toolchain used is arm-linux-gnueabihf-. So we do the build as follows:
This will create the uImage, zImage and dtbs files.
We use the debian rootfs: debian-9.2-minimal-armhf-2017-10-10.tar.xz
I create two SD card partitions. I do the following after the extraction of the above rootfs assuming the /dev/<partno> is mounted at /mnt/devmnt
To load the file we do:
After the above loading we do the following:
The BeagleBone Black should start booting. Use the username as debian and password as temppwd to login.
The above will cause a fault after mounting of the filesystem and running in if you use the Ubuntu tool chain as it. Use the Linaro tool chain which gets downloaded in the dl folder in the tree when build_kernel.sh is called.
BeagleBone Black is a really nice and capable SBC. I will document my Linux experiments similar to Wandboard here. We will first start with the Linux setup and installation.
I am going to the use Robert C Nelson (hereafter RCN) trees for building my kernel.
We have the BB Kernel tree here: https://github.com/RobertCNelson/bb-kernel.git
We do a git clone and git checkout 4.14-rc8-bone3. We can just call the build_kernel.sh which will build the kernel automatically. We can reuse the .config for our customization.
We can also use the bleeding edge tree: https://github.com/beagleboard/linux.git
In the above tree we can build the image manually. The baremetal toolchains arm-none-eabi- from the Ubuntu repository and the arm-eabi- from the ARM/Linaro toolchain will cause errors in the build. After observing the BB Kernel tree build messages I see that the toolchain used is arm-linux-gnueabihf-. So we do the build as follows:
1 2 | ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make bb.org_defconfig LOADADDR=0x80008000 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j10 uImage zImage dtbs modules |
This will create the uImage, zImage and dtbs files.
We use the debian rootfs: debian-9.2-minimal-armhf-2017-10-10.tar.xz
I create two SD card partitions. I do the following after the extraction of the above rootfs assuming the /dev/<partno> is mounted at /mnt/devmnt
1 2 3 | sudo tar xfvp rootfs.tar -C /mnt/devmnt sudo chown root:root /mnt/devmnt sudo chown 755 /mnt/devmnt |
To load the file we do:
1 2 | fatload mmc 0:1 0x80008000 uImage fatload mmc 0:1 0x8C008000 am335x-boneblack.dtb |
After the above loading we do the following:
1 2 | setenv bootargs console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait bootm 0x80008000 - 0x8C008000 |
The BeagleBone Black should start booting. Use the username as debian and password as temppwd to login.
The above will cause a fault after mounting of the filesystem and running in if you use the Ubuntu tool chain as it. Use the Linaro tool chain which gets downloaded in the dl folder in the tree when build_kernel.sh is called.
Saturday, 19 August 2017
Understanding linker scripts and walkthrough of it in MDK-OS.
I wanted to write about a certain complex topic called linker scripts. Although the syntax being simple the topic is very vast. I will be taking an example from my OS. From here it is possible to expand and build on top of it. I will discuss the basics of the topic and will expand as I implement further techniques.
Linker scripts are used by the linker (in GNU toolchain it is called ld). Linker scripts allow us to control the positioning and attributes of object code in the final output file. The linker "stitches" the various object code files into one single output file with instructions on how to position various "sections" of the program taken from the linker script file. The extension of a linker script is ".ld" or sometimes ".lds". The script is written using the linker command language.
Linker always uses a the linker script. If you don't supply any linker scripts the linker will use an internal linker script which is compiled into the linker executable file. You can check out what the default linker script is by typing:
You can provide a linker script by providing a -T option. In my Makefile for the loader and mdkos I have two variables LOADER_LDSCRIPT and OD_LDSCRIPT with strings -Tloader.lds and -Tmdkos.lds respectively.
As mentioned above the linker script combines different input files into a single output file. These files are in a special format called object file format. The files are called object files. Each of the object file has among other things called sections. The sections in input files are called input sections. Similarly the section in an output file is called an output section.
Each section in an object file has a name and size. Most sections also have an associated block of data called section contents. A section may be marked as loadable, which means that the contents should be loaded into memory when the output file is run. A section with no contents may be allocatable, which means that an area in memory should be set aside, but nothing in particular should be loaded there (in some cases this memory must be zeroed out). A section which is neither loadable nor allocatable typically contains some sort of debugging information.
You can see the different sections of an object file by using objdump with the -h option. For example to view the different sections in the mdk_loader elf file I input:
Every object file also has a list of symbols, known as the symbol table. A symbol may be defined or undefined. Each symbol has a name, and each defined symbol has an address, among other information. If you compile a C or C++ program into an object file, you will get a defined symbol for every defined function and global or static variable. Every undefined function or global variable which is referenced in the input file will become an undefined symbol.
You can check the different symbols in the object file using the -t option for the objdump or use nm.
For example:
Typically the different sections in your program and the place they reside can be:
Virtual memory address (VMA): This is the address the section will have when the output file is run. In the code this is the address which will be used as a reference by other parts of the code. Hence we would have to move code from the Load Memory Address to the Virtual Memory Address.
Load memory address (LMA): This the address the section will be loaded.
In most cases both the addresses will be the same. The case where they may differ is when say the .data section is loaded into ROM and then copied to RAM when the program starts up. In this case the ROM address would be the LMA and the RAM address is the VMA.
An interesting example I have encountered previously was a device with low RAM probably about 4MB. This device had various applications to simplify it was less than 4MB but if added together would be greater than 4MB, somewhere around 50 - 100 MB monolithic application. The technique is called overlaying. All the applications were loaded into a huge NOR flash. All the applications had overlapping memory addresses in the RAM i.e. all the applications had references starting from the same address in the RAM. This is called the VMA.
The application is a monolithic code. So the applications had been placed in the incrementing addresses i.e. the section was placed at incrementing address in the NOR flash. Now to load the application from the NOR flash to the RAM there was a small program called the loader. When a user wanted to go to a specific application he would select in the user interface (UI) and the loader would copy the application from the start address i.e. the LMA address and pastes it on to the RAM i.e. the VMA address and the program counter(PC) would jump to that particular address.
We can inform ld where to load various parts of the program in two ways.
The first is to assign names to various memory regions of our device and then direct each code or data section to the appropriate memory region. This is what is followed in my code.
The second method is to start the linker's current memory location counter at a known address (the start address of the first section of the memory to be populated) and emit sections one by one to the current location, manually incrementing this location counter as appropriate in order to skip "holes" in the memory map. The "holes" in the memory map can be peripheral memory mapping etc.
For eg:
In this script we know that the RAM of the S3C2440 starts at 0x30000000. So we set the location counter at that location in the RAM. The line . = 0x30000000 achieves this.
Next we tell ld which sections to include in the output file, where to emit them into memory and which sections of the input files should be mapped. The next 3 lines does this task. These lines basically say "collect all .text sections from the input files and emit them to a section called .text in the output file. Next collect all .data sections from the input file and emit them to a section called .data in the output file. Finally collect all .bss sections from the input file and emit them to a section called .bss in the output file".
Now I will describe some of the linker script examples in the MDK OS.
First we define the memory regions as follows:
In the above case we have
In this section we have .text section loaded onto the "sdram" region. After this we also have the .data section loaded onto the "sdram" region.
I have the __data_start__ = . and the __data_end__ = . which is extern'd in the code. These variables will be filled with the addresses of the start and end of the data section. Please note that the __data_start__ and __data_end__ is loaded with the VMA. In .data section the VMA and LMA is the same.
Next we have the following section:
In the above example I have kept the ".rodata" or the read-only data in the SDRAM. This will be moved to ROM later on.
Next we come to the .bss section which is the data section. All the data is clubbed and kept in the "sdram" memory region. We also setup the user, irq, fiq and svc stack sections each the size of 4KB. We also place markers which will be used in the assembly and C code for setup of stack.
Next we come to the usage of the VMA and LMA concepts and that is in the interrupt handlers. We have the ld script as follows:
In this we have the .vector_reloc section at sdram which is the LMA denoted by AT>sdram. The VMA is the vectors memory region which starts from 0x33F00000. Following this section is the .isr_handler section which is similar to above which has the LMA being in the SDRAM and the VMA being in the vectors memory region. We use LOADADDR to get the LMA of the section and SIZE to get the size of the section.
In the previous case the variables __irq_stack_bottom__ etc is loaded with the VMA. Since the LMA and the VMA are the same in it we do not bother to use the LOADADDR and SIZE functions.
How does all this come together?
The address generated and all the code references of the vector_reloc and isr_handler is the VMA. It is stored in the LMA though.The code for exception_vectors is present in os_vector.s in the section vector_reloc. The code snippet is as follows:
The code for exception handling is present in the file exception_handler.s and in the section isrhandler. The snippet of the code is as follows:
Please note that do_handle_irq contents and some other unrelated contents are replaced with "..." for clarity.
The objdump of the section is as follows run with the following command:
Now that we have all the data we can start analysing the dumps.
Firstly we verify the claim that all code references are using VMA regions. If we see the disassembly of the vector_reloc and isrhandler above we can see that the memory regions (the first column) are using the addresses from the vectors region which starts from 0x33F00000. After this the isrhandler follows which starts from 0x33F00040.
Because all references are in the 0x33F0000 range we have to load the code in that memory range from the part of the RAM pointed to by the LMA to the VMA. To get the address of the LMA we use the following code.
We extern the markers __exception_handler_start_addr__, __exception_handler_end_addr__ and __exception_vector_reloc_startaddr__,__exception_vector_reloc_endaddr__ .
The exception handler loading starts after the exception vector loading stops.
We get back to the objdump disassembly to analyse further the addresses. We see the loading to of the PC (Program counter) with the function address of the handler. We take the first example starting at 0x33F0000 which is ldr pc, =do_handle_reset.
The do_handle_reset symbol is located at 0x33F00040. To load this address we see that ldr PC, [PC, #24] (#24 is 0x18) which means load the contents of the memory present at PC+24. We face a small dilemma here. We see that the PC value is 0x33F00000. So the value after addition is 0x33F00018 (#24 is 0x18) but in the code we land to a value 0x59ff018 in that memory location 0x33F00018. Why is this?
According to the ARM guide we have the following:
Reading the program counter
When an instruction reads the PC, the value read depends on which instruction set it comes from:
For an ARM instruction, the value read is the address of the instruction plus 8 bytes. Bits [1:0] of this
value are always zero, because ARM instructions are always word-aligned.
Due to this we have actually have the PC value as 0x33F0000 + 0x8 when we do a read of the PC value in the LDR instruction. Hence PC value will be 0x33F00000 + 0x8 which is 0x33F00008. Next we have the addition of #24 which is 0x18 in hex which equals 0x33F00020. The value of that memory region is placed in the register PC. The value at that location is 0x33F00040. Hence the value of 0x33F00040 is placed in the PC which is address of the function do_handle_reset.
We observe something strange in the disassembly. We see the location 33F00020 has the following in the object dump.
What does mvnscc mean? Why do we have some instructions present there which does not make no sense? Well it stumped me for sometime and then I realized that it is just a value placed in the memory. The PC loads that value which is the address of the do_handle_reset hence loads the instruction from there. Why it shows an instruction? This is because the disassembler just blindly decodes the value present. How did I come to this conclusion? I simply changed the vectors address to 0x32F0000 which loaded another instruction which had the value 0x32Fxxxxx.
Finally how exactly do I make the interrupt handler jump to the address mentioned in the vectors when ARM states that the interrupt handlers should be in location 0x00000000? I just map the address 0x00000000 to the address 0x33F00000 in the MMU translation table. So when the CPU emits the address 0x00000000 it translates to 0x33F00000.
This concludes the post on linker scripts. I will add any new things to this post if I come across anything interesting or make things even more clearer with examples.
Finally I want to conclude with the memory map of the MDK OS.
Linker scripts are used by the linker (in GNU toolchain it is called ld). Linker scripts allow us to control the positioning and attributes of object code in the final output file. The linker "stitches" the various object code files into one single output file with instructions on how to position various "sections" of the program taken from the linker script file. The extension of a linker script is ".ld" or sometimes ".lds". The script is written using the linker command language.
Linker always uses a the linker script. If you don't supply any linker scripts the linker will use an internal linker script which is compiled into the linker executable file. You can check out what the default linker script is by typing:
1 | ld --verbose |
You can provide a linker script by providing a -T option. In my Makefile for the loader and mdkos I have two variables LOADER_LDSCRIPT and OD_LDSCRIPT with strings -Tloader.lds and -Tmdkos.lds respectively.
As mentioned above the linker script combines different input files into a single output file. These files are in a special format called object file format. The files are called object files. Each of the object file has among other things called sections. The sections in input files are called input sections. Similarly the section in an output file is called an output section.
Each section in an object file has a name and size. Most sections also have an associated block of data called section contents. A section may be marked as loadable, which means that the contents should be loaded into memory when the output file is run. A section with no contents may be allocatable, which means that an area in memory should be set aside, but nothing in particular should be loaded there (in some cases this memory must be zeroed out). A section which is neither loadable nor allocatable typically contains some sort of debugging information.
You can see the different sections of an object file by using objdump with the -h option. For example to view the different sections in the mdk_loader elf file I input:
1 | arm-none-eabi-objdump -h mdk_loader.elf |
Every object file also has a list of symbols, known as the symbol table. A symbol may be defined or undefined. Each symbol has a name, and each defined symbol has an address, among other information. If you compile a C or C++ program into an object file, you will get a defined symbol for every defined function and global or static variable. Every undefined function or global variable which is referenced in the input file will become an undefined symbol.
You can check the different symbols in the object file using the -t option for the objdump or use nm.
For example:
1 | arm-none-eabi-objdump -t mdk_loader.elf |
Typically the different sections in your program and the place they reside can be:
- Constant data: For example this can be const char teststr = "Test string". This type of information can safely be stored in ROM and used in place and need not be copied to say RAM.
- Initialized variables: For example int testint = 1234. This data my physically reside in RAM, the initial values to be loaded at boot time must be in ROM.
- Uninitialized variables: For example a declaration such as int testint;. These need not occupy any space in ROM. The start up code simply needs to allocate sufficient space in RAM for them, the linker needs to know how to resolve references to these variables.
- Startup code (hardware and C run-time initialization) code. This code is written in assembly and must be located at a specific place in ROM.
- Application code: This is distinct from startup code and usually doesn't have to reside anywhere specific in the memory map.
Virtual memory address (VMA): This is the address the section will have when the output file is run. In the code this is the address which will be used as a reference by other parts of the code. Hence we would have to move code from the Load Memory Address to the Virtual Memory Address.
Load memory address (LMA): This the address the section will be loaded.
In most cases both the addresses will be the same. The case where they may differ is when say the .data section is loaded into ROM and then copied to RAM when the program starts up. In this case the ROM address would be the LMA and the RAM address is the VMA.
An interesting example I have encountered previously was a device with low RAM probably about 4MB. This device had various applications to simplify it was less than 4MB but if added together would be greater than 4MB, somewhere around 50 - 100 MB monolithic application. The technique is called overlaying. All the applications were loaded into a huge NOR flash. All the applications had overlapping memory addresses in the RAM i.e. all the applications had references starting from the same address in the RAM. This is called the VMA.
The application is a monolithic code. So the applications had been placed in the incrementing addresses i.e. the section was placed at incrementing address in the NOR flash. Now to load the application from the NOR flash to the RAM there was a small program called the loader. When a user wanted to go to a specific application he would select in the user interface (UI) and the loader would copy the application from the start address i.e. the LMA address and pastes it on to the RAM i.e. the VMA address and the program counter(PC) would jump to that particular address.
We can inform ld where to load various parts of the program in two ways.
The first is to assign names to various memory regions of our device and then direct each code or data section to the appropriate memory region. This is what is followed in my code.
The second method is to start the linker's current memory location counter at a known address (the start address of the first section of the memory to be populated) and emit sections one by one to the current location, manually incrementing this location counter as appropriate in order to skip "holes" in the memory map. The "holes" in the memory map can be peripheral memory mapping etc.
For eg:
1 2 3 4 5 6 7 | SECTIONS
{
. = 0x30000000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
|
In this script we know that the RAM of the S3C2440 starts at 0x30000000. So we set the location counter at that location in the RAM. The line . = 0x30000000 achieves this.
Next we tell ld which sections to include in the output file, where to emit them into memory and which sections of the input files should be mapped. The next 3 lines does this task. These lines basically say "collect all .text sections from the input files and emit them to a section called .text in the output file. Next collect all .data sections from the input file and emit them to a section called .data in the output file. Finally collect all .bss sections from the input file and emit them to a section called .bss in the output file".
Now I will describe some of the linker script examples in the MDK OS.
First we define the memory regions as follows:
1 2 3 4 5 6 7 | MEMORY
{
sram : org = 0x00000000 , len = 0x1000
/*sdram : org = 0x30000000 , len = 0x4000000*/
sdram : org = 0x30000000 , len = 0x3F00000 /* 63MB RAM */
vectors : org = 0x33F00000 , len = 0x100000 /* Last 1MB for the isr handlers */
}
|
In the above case we have
- SRAM at location 0x0000 of size 4KB.
- SDRAM at location 0x30000000 of size 64MB but I have commented it out. Instead I am keeping the SDRAM region size of 63MB reserving the last 1MB.
- The last 1MB is reserved for the interrupt vectors and it is the vectors region.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | .text :
{
*(.text);
. = ALIGN(4);
} > sdram
.data :
{
__data_start__ = .;
*(.data);
. = ALIGN(4);
__data_end__ = .;
} > sdram
|
In this section we have .text section loaded onto the "sdram" region. After this we also have the .data section loaded onto the "sdram" region.
I have the __data_start__ = . and the __data_end__ = . which is extern'd in the code. These variables will be filled with the addresses of the start and end of the data section. Please note that the __data_start__ and __data_end__ is loaded with the VMA. In .data section the VMA and LMA is the same.
Next we have the following section:
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 26 27 28 29 30 | .rodata :
{
__rodata_start__ = .;
*(.rodata);
. = ALIGN(4);
__rodata_end__ = .;
} > sdram
.bss :
{
__bss_start__ = .;
*(.bss); *(COMMON)
__bss_end__ = .;
__usr_sys_stack_bottom__ = .;
. += 0x1000;
__usr_sys_stack_top__ = .;
__irq_stack_bottom__ = .;
. += 0x1000;
__irq_stack_top__ = .;
__fiq_stack_bottom__ = .;
. += 0x1000;
__fiq_stack_top__ = .;
__svc_stack_bottom__ = .;
. += 0x1000;
__svc_stack_top__ = .;
} > sdram
|
In the above example I have kept the ".rodata" or the read-only data in the SDRAM. This will be moved to ROM later on.
Next we come to the .bss section which is the data section. All the data is clubbed and kept in the "sdram" memory region. We also setup the user, irq, fiq and svc stack sections each the size of 4KB. We also place markers which will be used in the assembly and C code for setup of stack.
Next we come to the usage of the VMA and LMA concepts and that is in the interrupt handlers. We have the ld script as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | .vector_reloc :
{
*(.vector_reloc);
} >vectors AT>sdram
/* Get the lma address for the particular section */
__exception_vector_reloc_startaddr__ = LOADADDR(.vector_reloc);
__exception_vector_reloc_endaddr__ = LOADADDR(.vector_reloc) + SIZEOF(.vector_reloc);
/*
* Above SDRAM is where it will be stored in the file but address
* references will be in the addresses of the isr handler section
*/
.isrhandler :
{
*(.isrhandler);
} >vectors AT>sdram
__exception_handler_start_addr__ = LOADADDR(.isrhandler);
__exception_handler_end_addr__ = LOADADDR(.isrhandler) + SIZEOF(.isrhandler);
|
In this we have the .vector_reloc section at sdram which is the LMA denoted by AT>sdram. The VMA is the vectors memory region which starts from 0x33F00000. Following this section is the .isr_handler section which is similar to above which has the LMA being in the SDRAM and the VMA being in the vectors memory region. We use LOADADDR to get the LMA of the section and SIZE to get the size of the section.
In the previous case the variables __irq_stack_bottom__ etc is loaded with the VMA. Since the LMA and the VMA are the same in it we do not bother to use the LOADADDR and SIZE functions.
How does all this come together?
The address generated and all the code references of the vector_reloc and isr_handler is the VMA. It is stored in the LMA though.The code for exception_vectors is present in os_vector.s in the section vector_reloc. The code snippet is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | .section .vector_reloc,"ax" //Apparent fix for missing section when objcopy is to have allocatable and executable flags-"ax" //TODO: Understand the reason for the above flag. .code 32 .globl exception_vectors exception_vectors: ldr pc,=do_handle_reset //Reset vector ldr pc,=do_handle_undef //Undefined instruction ldr pc,=do_handle_swi //Software Interrupt ldr pc,=do_handle_pabt //Abort prefetch ldr pc,=do_handle_dabt //Abort data ldr pc,=do_handle_reserved //Reserved ldr pc,=do_handle_irq //IRQ ldr pc,=do_handle_fiq //FIQ .end |
The code for exception handling is present in the file exception_handler.s and in the section isrhandler. The snippet of the code is as follows:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | .section .isrhandler,"ax" .code 32 .globl do_handle_reset do_handle_reset: b do_handle_reset .globl do_handle_undef do_handle_undef: b do_handle_undef .globl do_handle_swi do_handle_swi: b do_handle_swi .globl do_handle_pabt do_handle_pabt: b do_handle_pabt .globl do_handle_dabt do_handle_dabt: b do_handle_dabt .globl do_handle_reserved do_handle_reserved: b do_handle_reserved .globl do_handle_irq do_handle_irq: ... ... .globl do_handle_fiq do_handle_fiq: b do_handle_fiq ... ... .end |
Please note that do_handle_irq contents and some other unrelated contents are replaced with "..." for clarity.
The objdump of the section is as follows run with the following command:
1 | arm-none-eabi-objdump -tDSl bin/mdk_os.elf |
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | Disassembly of section .vector_reloc: 33f00000 <exception_vectors>: exception_vectors(): 33f00000: e59ff018 ldr pc, [pc, #24] ; 33f00020 <exception_vectors+0x20> 33f00004: e59ff018 ldr pc, [pc, #24] ; 33f00024 <exception_vectors+0x24> 33f00008: e59ff018 ldr pc, [pc, #24] ; 33f00028 <exception_vectors+0x28> 33f0000c: e59ff018 ldr pc, [pc, #24] ; 33f0002c <exception_vectors+0x2c> 33f00010: e59ff018 ldr pc, [pc, #24] ; 33f00030 <exception_vectors+0x30> 33f00014: e59ff018 ldr pc, [pc, #24] ; 33f00034 <exception_vectors+0x34> 33f00018: e59ff018 ldr pc, [pc, #24] ; 33f00038 <exception_vectors+0x38> 33f0001c: e59ff018 ldr pc, [pc, #24] ; 33f0003c <exception_vectors+0x3c> 33f00020: 33f00040 mvnscc r0, #64 ; 0x40 33f00024: 33f00044 mvnscc r0, #68 ; 0x44 33f00028: 33f00048 mvnscc r0, #72 ; 0x48 33f0002c: 33f0004c mvnscc r0, #76 ; 0x4c 33f00030: 33f00050 mvnscc r0, #80 ; 0x50 33f00034: 33f00054 mvnscc r0, #84 ; 0x54 33f00038: 33f00058 mvnscc r0, #88 ; 0x58 33f0003c: 33f00098 mvnscc r0, #152 ; 0x98 Disassembly of section .isrhandler: 33f00040 <do_handle_reset>: do_handle_reset(): 33f00040: eafffffe b 33f00040 <do_handle_reset> 33f00044 <do_handle_undef>: do_handle_undef(): 33f00044: eafffffe b 33f00044 <do_handle_undef> 33f00048 <do_handle_swi>: do_handle_swi(): 33f00048: eafffffe b 33f00048 <do_handle_swi> 33f0004c <do_handle_pabt>: do_handle_pabt(): 33f0004c: eafffffe b 33f0004c <do_handle_pabt> 33f00050 <do_handle_dabt>: do_handle_dabt(): 33f00050: eafffffe b 33f00050 <do_handle_dabt> 33f00054 <do_handle_reserved>: do_handle_reserved(): 33f00054: eafffffe b 33f00054 <do_handle_reserved> 33f00058 <do_handle_irq>: do_handle_irq(): ... ... 33f00098 <do_handle_fiq>: do_handle_fiq(): 33f00098: eafffffe b 33f00098 <do_handle_fiq> |
Now that we have all the data we can start analysing the dumps.
Firstly we verify the claim that all code references are using VMA regions. If we see the disassembly of the vector_reloc and isrhandler above we can see that the memory regions (the first column) are using the addresses from the vectors region which starts from 0x33F00000. After this the isrhandler follows which starts from 0x33F00040.
Because all references are in the 0x33F0000 range we have to load the code in that memory range from the part of the RAM pointed to by the LMA to the VMA. To get the address of the LMA we use the following code.
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | extern char __exception_handler_start_addr__[]; extern char __exception_handler_end_addr__[]; extern char __exception_vector_reloc_startaddr__[]; extern char __exception_vector_reloc_endaddr__[]; static void setup_interrupt_vector_table() { /* * TODO: Optimize it to remove the extra index variables. Unoptimized only for test purposes. * */ char *vector_table = (char *)EXCEPTION_INTERRUPT_VECTOR_TABLE_START; /* * Need to get the lma of the code. * The __exception_vector_reloc_startaddr__ is the lma i.e. the generated * address in the file. I need to use this as the start address for the * later vectors and handlers. */ char *src = (char *)__exception_vector_reloc_startaddr__; uint32_t i = 0; for(i = (uint32_t)__exception_vector_reloc_startaddr__; i<(uint32_t)__exception_vector_reloc_endaddr__; i++) { *vector_table = *src; vector_table++; src++; } /* Continue with the same place for handler source */ for(i = (uint32_t)__exception_handler_start_addr__; i<(uint32_t)__exception_handler_end_addr__; i++) { *vector_table = *src; vector_table++; src++; } } |
We extern the markers __exception_handler_start_addr__, __exception_handler_end_addr__ and __exception_vector_reloc_startaddr__,__exception_vector_reloc_endaddr__ .
The exception handler loading starts after the exception vector loading stops.
We get back to the objdump disassembly to analyse further the addresses. We see the loading to of the PC (Program counter) with the function address of the handler. We take the first example starting at 0x33F0000 which is ldr pc, =do_handle_reset.
The do_handle_reset symbol is located at 0x33F00040. To load this address we see that ldr PC, [PC, #24] (#24 is 0x18) which means load the contents of the memory present at PC+24. We face a small dilemma here. We see that the PC value is 0x33F00000. So the value after addition is 0x33F00018 (#24 is 0x18) but in the code we land to a value 0x59ff018 in that memory location 0x33F00018. Why is this?
According to the ARM guide we have the following:
Reading the program counter
When an instruction reads the PC, the value read depends on which instruction set it comes from:
For an ARM instruction, the value read is the address of the instruction plus 8 bytes. Bits [1:0] of this
value are always zero, because ARM instructions are always word-aligned.
Due to this we have actually have the PC value as 0x33F0000 + 0x8 when we do a read of the PC value in the LDR instruction. Hence PC value will be 0x33F00000 + 0x8 which is 0x33F00008. Next we have the addition of #24 which is 0x18 in hex which equals 0x33F00020. The value of that memory region is placed in the register PC. The value at that location is 0x33F00040. Hence the value of 0x33F00040 is placed in the PC which is address of the function do_handle_reset.
We observe something strange in the disassembly. We see the location 33F00020 has the following in the object dump.
1 | 33f00020: 33f00040 mvnscc r0, #64 ; 0x40 |
What does mvnscc mean? Why do we have some instructions present there which does not make no sense? Well it stumped me for sometime and then I realized that it is just a value placed in the memory. The PC loads that value which is the address of the do_handle_reset hence loads the instruction from there. Why it shows an instruction? This is because the disassembler just blindly decodes the value present. How did I come to this conclusion? I simply changed the vectors address to 0x32F0000 which loaded another instruction which had the value 0x32Fxxxxx.
Finally how exactly do I make the interrupt handler jump to the address mentioned in the vectors when ARM states that the interrupt handlers should be in location 0x00000000? I just map the address 0x00000000 to the address 0x33F00000 in the MMU translation table. So when the CPU emits the address 0x00000000 it translates to 0x33F00000.
This concludes the post on linker scripts. I will add any new things to this post if I come across anything interesting or make things even more clearer with examples.
Finally I want to conclude with the memory map of the MDK OS.
Memory Map Documentation: ========================= +-------------------------+ ----> 0x00000000 | | ^ | Initial bootloader | |---> Stepping stone buffer. | (mdk_loader) | v +-------------------------+ ----> 0x00001000 | | | | | Peripheral memory map | | hole | . . . . . . +-------------------------+ ----> 0x30000000 | mdk_os (.text) | | . | | . | | mdk_os (.data) | | . | | . | | mdk_os (.rodata) | | . | | . | | mdk_os (.bss) | | . | | . | | mdk_os (.stack) | . . . . . . . . +-------------------------+ +-------------------------+ ----> 0x33F00000 | | | Interrupt Vector table | | (section .vector_reloc) | | | +-------------------------+ ----> 0x33F00020 | | | | | Interrupt handlers | | (section .isrhandler) | | | | | +-------------------------+ ----> 0x34000000
Subscribe to:
Posts (Atom)





