Comfused with AVR bootloader flash section

Go To Last Post
76 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

AmVRosia wrote:
If you refer back to older conversations, I cannot fit the whole of the bootloader at the Boot Flash Section, hence I had to split it (my bootloader is about 0x3500 words and the Boot Flash Section has max size 0x2000 words).

 

Now, I've totally lost track of this, and perhaps the "older conversations" would spread some light.

 

0x3500 is 13568 words, 27000 bytes.  A nearly-full Mega328 or Mega324.  That is "big iron" for almost all of my many scores of production AVR8 apps over the years.

 

But your bootloader needs to be that large?!?  Is there a complete AI engine in there?  How then can there be an Arduino bootloader that is somewhat nearly universally used, that is comprehensive and reliable and fits nicely into the much much smaller bootloader section of a '328?  And has been adapted for other image sources besides UART?

 

Yes, indeed, I've proceeded down a path in the past using initial assumptions that just turned too onerous.  But then I needed to back up and take a different direction rather than try to turn that sow's ear into a silk purse.

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Jul 19, 2021 - 03:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lee, I tend to agree that it sounds very large but just to say this is an AT90CAN128 and the bootloader protocol is CAN. Now I don't know how much a minimal CAN support stack occupies but it's probably going to be a wee bit bigger than your "normal" UARt driver or whatever.

 

The AT90CAN128 datasheet tells us that the four bootloader sizes are 512, 1024, 2048 and 4096 words but that latter one is therefore 8K bytes. You might have thought you could get enough of CAN into that space (and a smattering of SPM) just to support firmware packet delivery. But, then again, I don't know that much about Atmel CAN - perhaps a LOT of work is left to the stack author ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did some testing without interrupts and I managed to get the same functionality in bootloader without them.

If no interrupts are now needed, then can use the simple version in post #49. You can change the start address to whatever you now want ( 0xC000 word address, 0x18000 byte address, it now seems). The boot vector is fixed to 4 options in upper flash, and since not using interrupts now the only requirement is to get the reset vector code in the proper place which will jump to your bootloader code. You also get the vector table, but is harmless if not used.

 

As you need more than 8k of bootloader code, you make the bootloader size the smallest it can be (1024bytes), and the only code in that 1024bytes will be the vectors, and the flash writing code as they are the only ones required to be there. The reason for using the smallest size is because all the other code will still be in a .text section which will live below the bootloader, and you would otherwise have to split it up if the vectors were stuck in the middle.

 

fuses set to boot reset vector, bootsize is minimal value-

mcu reset -> reset vector (flash size-1024 bytes) -> reset 'jmp' to __init(or whatever) which will most likely be at the start of .text 0x18000 since you specified the text region start address as 0x18000 in the linker script (doesn't matter where in .text the reset vector jumps to, it will be in the .text section in any case). You now no longer need the use of the vectors since interrupts not in use (no need to touch IVSEL either). The only requirement left is for the flash writing code to live in the NRWW section, which is done by using the section attribute on its function(s) (.flashfuncs). The flash writing function will need to block until done, and re-enable the RWW section so you can then return to your bootloader code which is in the RWW section.

 

If you decide you want interrupts, you change nothing except to set IVSEL as now required, and make sure interrupts are off during a flash write as you cannot jump into the RWW section where your code is located.

 

-------------------0x0000 (word addresses)
normal vectors
normal app code

end app code
-------------------0xBFFF (app gets 96K)
-------------------0xC000 (32K remaining, 31K usable)

(.text)
bootloader code 

                   0xF000 NRWW section
-------------------0xFE00 (bootsize=1024 bytes)

(.bls)
reset vectors

(.flashfuncs)
flash write function
-------------------0xFFFF end

 

 

  bls    (rx)   : ORIGIN = 0x1FC00, LENGTH = 1024
  text   (rx)   : ORIGIN = 0x18000, LENGTH = 32k-1024

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


clawson wrote:
Now I don't know how much a minimal CAN support stack occupies but it's probably going to be a wee bit bigger than your "normal" UARt driver or whatever.

I do know that one could do a functional app with a Mega161/Mega162 with the satellite chip.  Now, when doing a bootloader app one has some control over the configurations at both ends, so "minimal" is indeed a key word -- just as with doing e.g. SD-card bootloader.  Right? ;)

 

In any case, I'd like to see the analysis of this needed space.

 

https://www.avrfreaks.net/forum/... LOL, in this thread I tried to talk the poster out of using a bootloader, CAN or otherwise.  But there is an awfully interesting mention:

PorinsR wrote:
I have found Atmel's app note and code for "Slim" CAN bootloader, but its written in IAR.

 

And indeed:  http://ww1.microchip.com/downloa...

So 27KB still seems excessive...

 

 

 

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Jul 19, 2021 - 06:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Further digging shows an 8K bootloader in app note AVR914 https://www.datasheetarchive.com...

MikeB talked of it here https://www.avrfreaks.net/forum/... and we know that he knows his way around a can.

 

These people https://www.can-cia.org/fileadmi... did a CANopen implementation in about 4KB.

 

There are other hits that may be pertinent with a Google search on "atmel AVR bootloader using "CAN" protocol"  .  But there is enough in a quick dig to seem to indicate several (many?) existing implementations in the 4KB to 8KB -- i.e. conventional AVR8 bootloader-section-sized -- implementations.  Thus, the thrust to invent a new solution with convoluted vector tables seems puzzingl.

 

Also interesting is a recent discussion on eliminating the four cycles to save/restore R24 when doing a minimal ISR.  So any of the jumpity-jump approaches will totally obliterate chances for minimal ISR handling.  Trampolines, anyone?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
... and perhaps the "older conversations" would spread some light.
#7's URL 

https://www.avrfreaks.net/forum/comfused-avr-bootloader-flash-section#comment-3138511

led to the OpenBLT bootloader.

theusch wrote:
A nearly-full Mega328 or Mega324.
Maybe port OpenBLT to a CAN PIC [CAN PIC <-> megaAVR or AVR Dx (megaAVR follow-on)]

 


homepage [OpenBLT Bootloader]

 

Microchip Delivers First 8-bit MCU Family for CAN FD Networks | Microchip Technology

PIC18F27Q84 - 8-bit Microcontrollers

PIC18F27Q84 microchipDIRECT (minimum 1.39USD each for 100)

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Now I don't know how much a minimal CAN support stack occupies but it's probably going to be a wee bit bigger than your "normal" UARt driver or whatever.
Similar

clawson wrote:
You might have thought you could get enough of CAN into that space (and a smattering of SPM) just to support firmware packet delivery.
May be akin to the program space of USB DFU is greater than USB CDC or USB HID (protocol makes the difference)

 

P.S.

Wasn't aware CAN is in hospitals.

CAN Applications | Controller Area Network (CAN) Overview - NI (second paragraph)

 


https://github.com/huukit/Atmega-CAN/tree/master/canbootloader/binaries

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


gchapman wrote:

Maybe port OpenBLT to a CAN PIC

 

I'm not keeping up any longer.  When I was your age, open-faced BLT:

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

theusch wrote:

 

AmVRosia wrote:
If you refer back to older conversations, I cannot fit the whole of the bootloader at the Boot Flash Section, hence I had to split it (my bootloader is about 0x3500 words and the Boot Flash Section has max size 0x2000 words).

 

Now, I've totally lost track of this, and perhaps the "older conversations" would spread some light.

 

0x3500 is 13568 words, 27000 bytes.  A nearly-full Mega328 or Mega324.  That is "big iron" for almost all of my many scores of production AVR8 apps over the years.

 

But your bootloader needs to be that large?!?  Is there a complete AI engine in there?  How then can there be an Arduino bootloader that is somewhat nearly universally used, that is comprehensive and reliable and fits nicely into the much much smaller bootloader section of a '328?  And has been adapted for other image sources besides UART?

 

Yes, indeed, I've proceeded down a path in the past using initial assumptions that just turned too onerous.  But then I needed to back up and take a different direction rather than try to turn that sow's ear into a silk purse.

 

 

To sum up and clarify a few things regarding the bootloader choice and size:

 

The actual size of the bootloader is a bit over 0x2000 bytes (sorry mistakenly I said words in the previous post)

 

That includes the:

CANBus,

XCP protocol over CAN which supports file transfer and some other features (and I think that we should focus more on that as a size increase suspect rather than the CAN driver), 

the UART with printf for debugging purposes (biggie too),

some GPIO control,

flash drivers and

I2C drivers for an external EEPROM.

 

If I remove the UART it just about fits under the 0x2000 margin. But for some reason, I could not make other parts to work and I did not had a debugging mechanism to know why.

I could develop debugging over CANBus but I might end up to the same size problem. Or alternatively in a future revision of the boards I am working on have the additional debug pin accessible by the programmer as I asked for (JTAG instead of ISP).
 

If you see the source code of Feaser OpenBLT they have created a struct of the flash layout, dividing it into sectors of 32kb which I divided further down to 8kb. Because I just about exceed the 8kb I have to reserve 2 sectors hence the 16kb and the address 0x4000 (address in .hex file). Then I started becoming greedy and since I have reserved so much space for the bootloader I added a few more features and now I am at specifically 0x311A total and after the revised architecture it looks like this:

.text              0x0001a000     0x296e

.bootloader     0x0001e000      0x7ac

 


 

 

Last Edited: Tue. Jul 20, 2021 - 11:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

I did some testing without interrupts and I managed to get the same functionality in bootloader without them.

If no interrupts are now needed, then can use the simple version in post #49. You can change the start address to whatever you now want ( 0xC000 word address, 0x18000 byte address, it now seems). The boot vector is fixed to 4 options in upper flash, and since not using interrupts now the only requirement is to get the reset vector code in the proper place which will jump to your bootloader code. You also get the vector table, but is harmless if not used.

 

As you need more than 8k of bootloader code, you make the bootloader size the smallest it can be (1024bytes), and the only code in that 1024bytes will be the vectors, and the flash writing code as they are the only ones required to be there. The reason for using the smallest size is because all the other code will still be in a .text section which will live below the bootloader, and you would otherwise have to split it up if the vectors were stuck in the middle.

 

fuses set to boot reset vector, bootsize is minimal value-

mcu reset -> reset vector (flash size-1024 bytes) -> reset 'jmp' to __init(or whatever) which will most likely be at the start of .text 0x18000 since you specified the text region start address as 0x18000 in the linker script (doesn't matter where in .text the reset vector jumps to, it will be in the .text section in any case). You now no longer need the use of the vectors since interrupts not in use (no need to touch IVSEL either). The only requirement left is for the flash writing code to live in the NRWW section, which is done by using the section attribute on its function(s) (.flashfuncs). The flash writing function will need to block until done, and re-enable the RWW section so you can then return to your bootloader code which is in the RWW section.

 

If you decide you want interrupts, you change nothing except to set IVSEL as now required, and make sure interrupts are off during a flash write as you cannot jump into the RWW section where your code is located.

 

-------------------0x0000 (word addresses)
normal vectors
normal app code

end app code
-------------------0xBFFF (app gets 96K)
-------------------0xC000 (32K remaining, 31K usable)

(.text)
bootloader code 

                   0xF000 NRWW section
-------------------0xFE00 (bootsize=1024 bytes)

(.bls)
reset vectors

(.flashfuncs)
flash write function
-------------------0xFFFF end

 

 

  bls    (rx)   : ORIGIN = 0x1FC00, LENGTH = 1024
  text   (rx)   : ORIGIN = 0x18000, LENGTH = 32k-1024

 

I think I follow this design, but I am not 100% sure, I will come back to that and check it in more detail.

 

I have removed the interrupts, I have set the reset vector to jump to NRWW section, and somehow it works which I do not fully understand yet. How does it know where my bootloader starts?
The .text is at 0x0001a000 and includes main() as well as everything else

The .bootloader is at 0x0001e000 and it only includes the flash write and flash erase functions

 

My application at 0x0 is working fine with its interrupts. Sometimes I think when I jump from the bootloader to the application I get problems, but I have changed a few things and I need to spend more time testing. I was wondering is it best for the bootloader to change the reset vector to point to address 0x0 just before the jump? Or is it best for the application to change the reset vector to point to address 0x0 during its initialisation? What if the application is corrupted? How do we get back to the bootloader execution if the reset vector points at 0x0?

Last Edited: Tue. Jul 20, 2021 - 11:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AmVRosia wrote:
The actual size of the bootloader is a bit over 0x2000 bytes
So close ... well done!

Bootloader documentation sometimes states a specific toolchain configuration; might try different versions of the compiler and/or different compiler makes (several for C on AVR)

AmVRosia wrote:
the UART with printf for debugging purposes (biggie too),
Microchip Data Visualizer (extension or executable) can do the formatting in-lieu of the AVR.

AmVRosia wrote:
Or alternatively in a future revision of the boards I am working on have the additional debug pin accessible by the programmer as I asked for (JTAG instead of ISP).
If there's a spare port then consider requesting that to a logic analyzer connector.

JTAG will enable a low-rate no-breakpoint communication between Microchip Studio and the AVR (OCDR register)

A logic analyzer enables high-rate low-latency communication via an AVR port.

 


Terminal Example Code | Data Visualizer Software User's Guide

 

Troubleshooting real-time software issues using a logic analyzer - Embedded.com

Logic-to-2x4 Header (Gen 2) | Saleae Cart

IDR Events | Microchip Studio  (OCDR)

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

AmVRosia wrote:
Or alternatively in a future revision of the boards I am working on have the additional debug pin accessible by the programmer as I asked for (JTAG instead of ISP).
If there's a spare port then consider requesting that to a logic analyzer connector.

JTAG will enable a low-rate no-breakpoint communication between Microchip Studio and the AVR (OCDR register)

A logic analyzer enables high-rate low-latency communication via an AVR port.

 

Thanks. Could you please post more information on hardware setup?

 

Is there any way of accessing any breakpoints in AVR?

 

https://microchipsupport.force.c...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're welcome.

AmVRosia wrote:
Could you please post more information on hardware setup?
If EBI (XMEM) isn't in use then port A or port C to a header.

Header layout depends on the logic analyzer though Mictor is a somewhat common connector.

Other than a complete port, a spare SPI may be fast enough and may be preferred as SPI can be the source or sink of biphase (clock recovery from one signal as signal is data plus clock)

AmVRosia wrote:
Is there any way of accessing any breakpoints in AVR?
Yes by enabling the OCD (OCDEN)

In linked article, Atmel Studio has been replaced by Microchip Studio.

 


AT90CAN32 AT90CAN64 AT90CAN128 - doc7679.pdf

[page 5, package lower right corner]

Pinout AT90CAN32/64/128 - TQFP

MA134A Mictor Adapter for Intronix Logic Analyzers

Getting Started with Configurable Custom Logic (CCL) (mid-page for bi-phase)

The Art of Electronics 3rd Edition | by Horowitz and Hill

Download a sample chapter

[page 19, middle of left column]

14.7.10 Biphase coding1041

A biphase encoder and decoder can be in a sPLD.

 

Microchip Studio (operator's manual)

Interface Settings | Microchip Studio

Microchip Studio for AVR® and SAM Devices | Microchip Technology

Connecting to a JTAG Target | Atmel-ICE

Pinouts for Interfaces | MPLAB® PICkit™ 4 In-Circuit Debugger User's Guide

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gchapman wrote:

JTAG will enable a low-rate no-breakpoint communication between Microchip Studio and the AVR (OCDR register)

 

Yes by enabling the OCD (OCDEN)

The ISP does not allow breakpoints.

As I understand from the datasheet the JTAG will allow debugging, but you mentioned it does not.

I think the OCDEN fuse is controlled by the IDE or the programmer when the debugging mode is selected.

 

gchapman wrote:

If EBI (XMEM) isn't in use then port A or port C to a header.
Header layout depends on the logic analyzer though Mictor is a somewhat common connector.

Other than a complete port, a spare SPI may be fast enough and maybe preferred as SPI can be the source or sink of biphase (clock recovery from one signal as signal is data plus clock)
 

MA134A Mictor Adapter for Intronix Logic Analyzers

Getting Started with Configurable Custom Logic (CCL) (mid-page for bi-phase)

The Art of Electronics 3rd Edition | by Horowitz and Hill

Download a sample chapter

[page 19, middle of left column]

14.7.10 Biphase coding1041

A biphase encoder and decoder can be in a sPLD.


We do have a spare port A.

I guess I will need another microcontroller to decode the data? Unless the logic analyzer does it itself. But what is the benefit on bare metal projects to implement this? We do not do any DSP to require speed and real-time data analysis.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AmVRosia wrote:

I think I follow this design, but I am not 100% sure, I will come back to that and check it in more detail.

 

I have removed the interrupts, I have set the reset vector to jump to NRWW section, and somehow it works which I do not fully understand yet. How does it know where my bootloader starts?
The .text is at 0x0001a000 and includes main() as well as everything else

The .bootloader is at 0x0001e000 and it only includes the flash write and flash erase functions

 

My application at 0x0 is working fine with its interrupts. Sometimes I think when I jump from the bootloader to the application I get problems, but I have changed a few things and I need to spend more time testing. I was wondering is it best for the bootloader to change the reset vector to point to address 0x0 just before the jump? Or is it best for the application to change the reset vector to point to address 0x0 during its initialisation? What if the application is corrupted? How do we get back to the bootloader execution if the reset vector points at 0x0?


It looks like things are as I described here and everything looks like it is working fine so far. But the fact that I still do not understand why it works like that is still scary for future outcomes :-D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


AmVRosia wrote:
but you mentioned it does not.
then I'm mistaken.

AmVRosia wrote:
Unless the logic analyzer does it itself.
Indeed

AmVRosia wrote:
But what is the benefit on bare metal projects to implement this?
No breakpoints, no tracepoints, diagnostic data flow (other)

 


Troubleshooting real-time software issues using a logic analyzer - Embedded.com

by Dave Stewart [director of Research and Systems Integration at InHand Electronics ]

...

...

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Hello all,

 

I am still having problems with the design I chose.

 

To recap the previous conversations, I ended up using a bootloader that has some features we were interested in. I have expanded the source code on those and I have added more features. The bootloader does not use interrupts for simplicity. The bootloader is bigger than the boot section that the AVR chip provides (please let's assume that changing the bootloader is not the preferrable option).

I had to split the bootloader to a section that lives in flash address 0xD000 (all the other functions) and flash address 0xF000 (all the flash manipulation functions, otherwise they will not work). Looking at the .srec and .map file it looks like that is the case (0xFFs until byte 0x1A000, then something, then few more 0xFFs until 0x1E000, then something else, then few 0xFFs until the end of the file).

The bootloader accepts the application firmware via CANBus and writes those at the beginning of the flash from 0x0000 to 0xCFFF.

The fuse setting for highrst is set (explecting to reboot at bootloader section).

The intention was/is alwas to boot in the bootloader, and then if a valid firmware application exists in flash, jump to the application. If no firmware application exists in flash, stay in the bootloader and wait for a firwmare transfer.

 

What is really happening is:

If the bootloader is on its own within the flash it works as expected. It no issues after reboot, runs again and waits for firmware transfer.

If a firmware transfer takes place, then after every reboot the AVR always jumps to the application section and runs the application firmware. I have the impression that once in a while it stucks for a minute without responding after reboot and then recovers and starts the application.

If during file transfer there is power loss or CANBus cable removal, the AVR gets briked and in order to work again it has to be re flashed via the programmer.

When I trigger the file transfer within the application firmware, I need to jump to address 0xD000 within the application in order for the bootloader to start working again, instead of address 0xF000. The hardware reset does not work. I do not understand how that reset vector works. I am not that confident on extracting information from the .map file either.

 

Bootloader segment at 0xF000

The rest of the firmware at 0x1A000

Fuses

srec contents

 

Part of the .map file

Address of section .bootloader set to 0x1e000
Address of section .text set to 0x1a000
START GROUP
LOAD c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a
LOAD c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a
LOAD c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libc.a
LOAD C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51\libat90can128.a
END GROUP
                0x00000000                __TEXT_REGION_ORIGIN__ = DEFINED (__TEXT_REGION_ORIGIN__)?__TEXT_REGION_ORIGIN__:0x0
                0x00800100                __DATA_REGION_ORIGIN__ = DEFINED (__DATA_REGION_ORIGIN__)?__DATA_REGION_ORIGIN__:0x800100
                0x00020000                __TEXT_REGION_LENGTH__ = DEFINED (__TEXT_REGION_LENGTH__)?__TEXT_REGION_LENGTH__:0x20000
                0x0000ff00                __DATA_REGION_LENGTH__ = DEFINED (__DATA_REGION_LENGTH__)?__DATA_REGION_LENGTH__:0xff00
                0x00010000                __EEPROM_REGION_LENGTH__ = DEFINED (__EEPROM_REGION_LENGTH__)?__EEPROM_REGION_LENGTH__:0x10000
                [0x00000003]                __FUSE_REGION_LENGTH__ = DEFINED (__FUSE_REGION_LENGTH__)?__FUSE_REGION_LENGTH__:0x400
                0x00000400                __LOCK_REGION_LENGTH__ = DEFINED (__LOCK_REGION_LENGTH__)?__LOCK_REGION_LENGTH__:0x400
                0x00000400                __SIGNATURE_REGION_LENGTH__ = DEFINED (__SIGNATURE_REGION_LENGTH__)?__SIGNATURE_REGION_LENGTH__:0x400
                0x00000400                __USER_SIGNATURE_REGION_LENGTH__ = DEFINED (__USER_SIGNATURE_REGION_LENGTH__)?__USER_SIGNATURE_REGION_LENGTH__:0x400

.hash
 *(.hash)

.dynsym
 *(.dynsym)

.dynstr
 *(.dynstr)

.gnu.version
 *(.gnu.version)

.gnu.version_d
 *(.gnu.version_d)

.gnu.version_r
 *(.gnu.version_r)

.rel.init
 *(.rel.init)

.rela.init
 *(.rela.init)

.rel.text
 *(.rel.text)
 *(.rel.text.*)
 *(.rel.gnu.linkonce.t*)

.rela.text
 *(.rela.text)
 *(.rela.text.*)
 *(.rela.gnu.linkonce.t*)

.rel.fini
 *(.rel.fini)

.rela.fini
 *(.rela.fini)

.rel.rodata
 *(.rel.rodata)
 *(.rel.rodata.*)
 *(.rel.gnu.linkonce.r*)

.rela.rodata
 *(.rela.rodata)
 *(.rela.rodata.*)
 *(.rela.gnu.linkonce.r*)

.rel.data
 *(.rel.data)
 *(.rel.data.*)
 *(.rel.gnu.linkonce.d*)

.rela.data
 *(.rela.data)
 *(.rela.data.*)
 *(.rela.gnu.linkonce.d*)

.rel.ctors
 *(.rel.ctors)

.rela.ctors
 *(.rela.ctors)

.rel.dtors
 *(.rel.dtors)

.rela.dtors
 *(.rela.dtors)

.rel.got
 *(.rel.got)

.rela.got
 *(.rela.got)

.rel.bss
 *(.rel.bss)

.rela.bss
 *(.rela.bss)

.rel.plt
 *(.rel.plt)

.rela.plt
 *(.rela.plt)

.text           0x0001a000     0x2934
 *(.vectors)
 .vectors       0x0001a000       0x94 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
                0x0001a000                __vector_default
                0x0001a000                __vectors
 *(.vectors)
 *(.progmem.gcc*)
 .progmem.gcc_sw_table.GPIO_PinDirection
                0x0001a094        0xe Drivers/gpio.o
 .progmem.gcc_sw_table.GPIO_PinWrite
                0x0001a0a2        0xe Drivers/gpio.o
 .progmem.gcc_sw_table.GPIO_PinRead
                0x0001a0b0        0xe Drivers/gpio.o
                0x0001a0be                . = ALIGN (0x2)
                0x0001a0be                __trampolines_start = .
 *(.trampolines)
 .trampolines   0x0001a0be        0x0 linker stubs
 *(.trampolines*)
                0x0001a0be                __trampolines_end = .
 *libprintf_flt.a:*(.progmem.data)
 *libc.a:*(.progmem.data)
 *(.progmem*)
                0x0001a0be                . = ALIGN (0x2)
 *(.jumptables)
 *(.jumptables*)
 *(.lowtext)
 *(.lowtext*)
                0x0001a0be                __ctors_start = .
 *(.ctors)
                0x0001a0be                __ctors_end = .
                0x0001a0be                __dtors_start = .
 *(.dtors)
                0x0001a0be                __dtors_end = .
 SORT(*)(.ctors)
 SORT(*)(.dtors)
 *(.init0)
 .init0         0x0001a0be        0x0 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
                0x0001a0be                __init
 *(.init0)
 *(.init1)
 *(.init1)
 *(.init2)
 .init2         0x0001a0be        0xc C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
 *(.init2)
 *(.init3)
 *(.init3)
 *(.init4)
 .init4         0x0001a0ca       0x1a c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_copy_data.o)
                0x0001a0ca                __do_copy_data
 .init4         0x0001a0e4       0x10 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_clear_bss.o)
                0x0001a0e4                __do_clear_bss
 *(.init4)
 *(.init5)
 *(.init5)
 *(.init6)
 *(.init6)
 *(.init7)
 *(.init7)
 *(.init8)
 *(.init8)
 *(.init9)
 .init9         0x0001a0f4        0x8 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
 *(.init9)
 *(.text)
 .text          0x0001a0fc        0x2 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
                0x0001a0fc                __vector_22
                0x0001a0fc                __vector_28
                0x0001a0fc                __vector_1
                0x0001a0fc                __vector_32
                0x0001a0fc                __vector_34
                0x0001a0fc                __vector_24
                0x0001a0fc                __vector_12
                0x0001a0fc                __bad_interrupt
                0x0001a0fc                __vector_6
                0x0001a0fc                __vector_31
                0x0001a0fc                __vector_35
                0x0001a0fc                __vector_3
                0x0001a0fc                __vector_23
                0x0001a0fc                __vector_30
                0x0001a0fc                __vector_25
                0x0001a0fc                __vector_11
                0x0001a0fc                __vector_13
                0x0001a0fc                __vector_7
                0x0001a0fc                __vector_27
                0x0001a0fc                __vector_5
                0x0001a0fc                __vector_33
                0x0001a0fc                __vector_4
                0x0001a0fc                __vector_9
                0x0001a0fc                __vector_2
                0x0001a0fc                __vector_21
                0x0001a0fc                __vector_15
                0x0001a0fc                __vector_36
                0x0001a0fc                __vector_29
                0x0001a0fc                __vector_8
                0x0001a0fc                __vector_26
                0x0001a0fc                __vector_14
                0x0001a0fc                __vector_10
                0x0001a0fc                __vector_16
                0x0001a0fc                __vector_20
                0x0001a0fe                . = ALIGN (0x2)
 *(.text.*)
 .text.prepare_eeprom
                0x0001a0fe       0x42 backup_hal.o
                0x0001a0fe                prepare_eeprom
 .text.handle_last_data
                0x0001a140       0x48 backup_hal.o
                0x0001a140                handle_last_data
 .text.detect_firmware_end_addr
                0x0001a188       0x5e backup_hal.o
                0x0001a188                detect_firmware_end_addr
 .text.recover_firmware
                0x0001a1e6      0x1e8 backup_hal.o
                0x0001a1e6                recover_firmware
 .text.AssertFailure
                0x0001a3ce        0x4 Bootloader/assert.o
                0x0001a3ce                AssertFailure
 .text.BackDoorCheck
                0x0001a3d2       0x76 Bootloader/backdoor.o
                0x0001a3d2                BackDoorCheck
 .text.BackDoorRestartTimer
                0x0001a448       0x1c Bootloader/backdoor.o
                0x0001a448                BackDoorRestartTimer
 .text.BackDoorInit
                0x0001a464        0xa Bootloader/backdoor.o
                0x0001a464                BackDoorInit
 .text.BootInit
                0x0001a46e        0x6 Bootloader/boot.o
                0x0001a46e                BootInit
 .text.BootTask
                0x0001a474        0x2 Bootloader/boot.o
                0x0001a474                BootTask
 .text.CanInit  0x0001a476        0x2 Bootloader/can.o
                0x0001a476                CanInit
 .text.CanTransmitPacket
                0x0001a478       0xa6 Bootloader/can.o
                0x0001a478                CanTransmitPacket
 .text.receive_host_can_message
                0x0001a51e       0x9c Bootloader/can.o
                0x0001a51e                receive_host_can_message
 .text.ComInit  0x0001a5ba        0xc Bootloader/com.o
                0x0001a5ba                ComInit
 .text.ComTask  0x0001a5c6        0xe Bootloader/com.o
                0x0001a5c6                ComTask
 .text.ComFree  0x0001a5d4        0x2 Bootloader/com.o
                0x0001a5d4                ComFree
 .text.ComTransmitPacket
                0x0001a5d6        0xc Bootloader/com.o
                0x0001a5d6                ComTransmitPacket
 .text.ComGetActiveInterfaceMaxTxLen
                0x0001a5e2       0x1c Bootloader/com.o
                0x0001a5e2                ComGetActiveInterfaceMaxTxLen
 .text.ComGetActiveInterfaceMaxRxLen
                0x0001a5fe        0x2 Bootloader/com.o
                0x0001a5fe                ComGetActiveInterfaceMaxRxLen
 .text.ComIsConnected
                0x0001a600        0xe Bootloader/com.o
                0x0001a600                ComIsConnected
 .text.CopService
                0x0001a60e        0x2 Bootloader/cop.o
                0x0001a60e                CopService
 .text.CpuStartUserProgram
                0x0001a610       0x50 Bootloader/cpu.o
                0x0001a610                CpuStartUserProgram
 .text.CpuMemCopy
                0x0001a660       0x54 Bootloader/cpu.o
                0x0001a660                CpuMemCopy
 .text.CpuMemSet
                0x0001a6b4       0x30 Bootloader/cpu.o
                0x0001a6b4                CpuMemSet
 .text.CpuIrqEnable
                0x0001a6e4        0x4 Bootloader/cpu_comp.o
                0x0001a6e4                CpuIrqEnable
 .text.FlashErase
                0x0001a6e8      0x1ec Bootloader/flash.o
                0x0001a6e8                FlashErase
 .text.FlashGetUserProgBaseAddress
                0x0001a8d4        0x8 Bootloader/flash.o
                0x0001a8d4                FlashGetUserProgBaseAddress
 .text.FlashGetEndAddress
                0x0001a8dc        0xa Bootloader/flash.o
                0x0001a8dc                FlashGetEndAddress
 .text.XcpGetSeedHook
                0x0001a8e6        0xe Bootloader/hooks.o
                0x0001a8e6                XcpGetSeedHook
 .text.XcpVerifyKeyHook
                0x0001a8f4       0x12 Bootloader/hooks.o
                0x0001a8f4                XcpVerifyKeyHook
 .text.LedBlinkTask
                0x0001a906       0x88 Bootloader/led.o
                0x0001a906                LedBlinkTask
 .text.NvmInit  0x0001a98e        0x4 Bootloader/nvm.o
                0x0001a98e                NvmInit
 .text.NvmWrite
                0x0001a992        0xe Bootloader/nvm.o
                0x0001a992                NvmWrite
 .text.NvmErase
                0x0001a9a0        0x2 Bootloader/nvm.o
                0x0001a9a0                NvmErase
 .text.NvmVerifyChecksum
                0x0001a9a2        0x4 Bootloader/nvm.o
                0x0001a9a2                NvmVerifyChecksum
 .text.NvmDone  0x0001a9a6        0xe Bootloader/nvm.o
                0x0001a9a6                NvmDone
 .text.TimerGet
                0x0001a9b4       0x12 Bootloader/timer.o
                0x0001a9b4                TimerGet
 .text.TimerInterrupt
                0x0001a9c6       0x28 Bootloader/timer.o
                0x0001a9c6                TimerInterrupt
 .text.TimerUpdate
                0x0001a9ee        0x2 Bootloader/timer.o
                0x0001a9ee                TimerUpdate
 .text.XcpSetCtoError
                0x0001a9f0       0x18 Bootloader/xcp.o
 .text.XcpInit  0x0001aa08       0x28 Bootloader/xcp.o
                0x0001aa08                XcpInit
 .text.XcpIsConnected
                0x0001aa30        0xe Bootloader/xcp.o
                0x0001aa30                XcpIsConnected
 .text.XcpPacketTransmitted
                0x0001aa3e        0x6 Bootloader/xcp.o
                0x0001aa3e                XcpPacketTransmitted
 .text.XcpPacketReceived
                0x0001aa44      0x67c Bootloader/xcp.o
                0x0001aa44                XcpPacketReceived
 .text.i2c_go_to_eeprom_register
                0x0001b0c0       0x1a config_hal.o
                0x0001b0c0                i2c_go_to_eeprom_register
 .text.i2c_read_dword_eeprom
                0x0001b0da       0x56 config_hal.o
                0x0001b0da                i2c_read_dword_eeprom
 .text._can_init
                0x0001b130       0x3a Drivers/ASTCanLib.o
                0x0001b130                _can_init
 .text.setGeneralCallback
                0x0001b16a        0xa Drivers/avr_can.o
                0x0001b16a                setGeneralCallback
 .text.enable_interrupt
                0x0001b174       0x44 Drivers/avr_can.o
                0x0001b174                enable_interrupt
 .text.disable_interrupt
                0x0001b1b8       0x56 Drivers/avr_can.o
                0x0001b1b8                disable_interrupt
 .text.mailbox_set_MOb_index
                0x0001b20e       0x14 Drivers/avr_can.o
                0x0001b20e                mailbox_set_MOb_index
 .text.mailbox_read
                0x0001b222      0x10c Drivers/avr_can.o
                0x0001b222                mailbox_read
 .text.mailbox_set_id
                0x0001b32e       0xda Drivers/avr_can.o
                0x0001b32e                mailbox_set_id
 .text.mailbox_set_accept_mask
                0x0001b408       0xaa Drivers/avr_can.o
                0x0001b408                mailbox_set_accept_mask
 .text.setNumTXBoxes
                0x0001b4b2       0x6e Drivers/avr_can.o
                0x0001b4b2                setNumTXBoxes
 .text.mailbox_tx_frame
                0x0001b520       0x46 Drivers/avr_can.o
                0x0001b520                mailbox_tx_frame
 .text.sendFrame
                0x0001b566      0x1c4 Drivers/avr_can.o
                0x0001b566                sendFrame
 .text.setRXFilterMailbox
                0x0001b72a       0x90 Drivers/avr_can.o
                0x0001b72a                setRXFilterMailbox
 .text.watchFor
                0x0001b7ba       0x40 Drivers/avr_can.o
                0x0001b7ba                watchFor
 .text.mailbox_int_handler
                0x0001b7fa      0x1fa Drivers/avr_can.o
                0x0001b7fa                mailbox_int_handler
 .text.interruptHandler
                0x0001b9f4       0x60 Drivers/avr_can.o
                0x0001b9f4                interruptHandler
 .text.__vector_18
                0x0001ba54       0x62 Drivers/avr_can.o
                0x0001ba54                __vector_18
 .text.__vector_19
                0x0001bab6       0x32 Drivers/avr_can.o
                0x0001bab6                __vector_19
 .text.can_clear_all_mob
                0x0001bae8       0x20 Drivers/can_drv.o
                0x0001bae8                can_clear_all_mob
 .text.can_init
                0x0001bb08       0x8a Drivers/can_lib.o
                0x0001bb08                can_init
 .text.GPIO_PinDirection
                0x0001bb92      0x19a Drivers/gpio.o
                0x0001bb92                GPIO_PinDirection
 .text.GPIO_PinWrite
                0x0001bd2c      0x19a Drivers/gpio.o
                0x0001bd2c                GPIO_PinWrite
 .text.GPIO_PinRead
                0x0001bec6       0x4c Drivers/gpio.o
                0x0001bec6                GPIO_PinRead
 .text.i2c_init
                0x0001bf12       0x12 Drivers/i2c.o
                0x0001bf12                i2c_init
 .text.I2C_Start
                0x0001bf24       0x10 Drivers/i2c.o
                0x0001bf24                I2C_Start
 .text.I2C_Stop
                0x0001bf34       0x14 Drivers/i2c.o
                0x0001bf34                I2C_Stop
 .text.I2C_Write
                0x0001bf48       0x14 Drivers/i2c.o
                0x0001bf48                I2C_Write
 .text.I2C_Read
                0x0001bf5c       0x1c Drivers/i2c.o
                0x0001bf5c                I2C_Read
 .text.UART_SetBaudRate
                0x0001bf78       0x5a Drivers/uart.o
                0x0001bf78                UART_SetBaudRate
 .text.uart_init
                0x0001bfd2       0x12 Drivers/uart.o
                0x0001bfd2                uart_init
 .text.UART_TxChar
                0x0001bfe4        0xe Drivers/uart.o
                0x0001bfe4                UART_TxChar
 .text.UART_TxNumber.part.0
                0x0001bff2       0x60 Drivers/uart.o
 .text.UART_TxString
                0x0001c052       0x16 Drivers/uart.o
                0x0001c052                UART_TxString
 .text.UART_TxNumber
                0x0001c068      0x11c Drivers/uart.o
                0x0001c068                UART_TxNumber
 .text.UART_TxFloatNumber
                0x0001c184       0x5e Drivers/uart.o
                0x0001c184                UART_TxFloatNumber
 .text.UART_Printf
                0x0001c1e2      0x314 Drivers/uart.o
                0x0001c1e2                UART_Printf
 .text.__vector_17
                0x0001c4f6       0x94 Drivers/wiring.o
                0x0001c4f6                __vector_17
 .text.avr-libc.fplib
                0x0001c58a        0xa c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(addsf3.o)
                0x0001c58a                __subsf3
                0x0001c58c                __addsf3
 .text.avr-libc.fplib
                0x0001c594       0xc0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(addsf3x.o)
                0x0001c5ae                __addsf3x
 .text.avr-libc.fplib
                0x0001c654       0x58 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fixunssfsi.o)
                0x0001c654                __fixunssfsi
 .text.avr-libc.fplib
                0x0001c6ac       0x7a c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(floatsisf.o)
                0x0001c6ac                __floatunsisf
                0x0001c6b0                __floatsisf
 .text.avr-libc.fplib
                0x0001c726        0xc c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_inf.o)
                0x0001c726                __fp_inf
 .text.avr-libc.fplib
                0x0001c732        0x6 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_nan.o)
                0x0001c732                __fp_nan
 .text.avr-libc.fplib
                0x0001c738        0xe c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_pscA.o)
                0x0001c738                __fp_pscA
 .text.avr-libc.fplib
                0x0001c746        0xe c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_pscB.o)
                0x0001c746                __fp_pscB
 .text.avr-libc.fplib
                0x0001c754       0x22 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_round.o)
                0x0001c754                __fp_round
 .text.avr-libc.fplib
                0x0001c776       0x44 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_split3.o)
                0x0001c776                __fp_split3
                0x0001c786                __fp_splitA
 .text.avr-libc.fplib
                0x0001c7ba        0xe c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(fp_zero.o)
                0x0001c7ba                __fp_zero
                0x0001c7bc                __fp_szero
 .text.avr-libc.fplib
                0x0001c7c8        0x4 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(mulsf3.o)
                0x0001c7c8                __mulsf3
 .text.avr-libc.fplib
                0x0001c7cc       0xc2 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libm.a(mulsf3x.o)
                0x0001c7e0                __mulsf3x
                0x0001c7e4                __mulsf3_pse
 .text.libgcc.div
                0x0001c88e       0x44 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_udivmodsi4.o)
                0x0001c88e                __udivmodsi4
 .text.libgcc   0x0001c8d2       0x12 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_tablejump2.o)
                0x0001c8d2                __tablejump2__
 .text.libgcc.mul
                0x0001c8e4        0xc c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_mulshisi3.o)
                0x0001c8e4                __mulshisi3
                0x0001c8e8                __mulohisi3
 .text.libgcc.mul
                0x0001c8f0       0x14 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_muluhisi3.o)
                0x0001c8f0                __muluhisi3
 .text.libgcc.mul
                0x0001c904       0x1e c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_umulhisi3.o)
                0x0001c904                __umulhisi3
 .text.avr-libc
                0x0001c922        0xe c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/lib/avr51\libc.a(memset.o)
                0x0001c922                memset
                0x0001c930                . = ALIGN (0x2)
 *(.fini9)
 .fini9         0x0001c930        0x0 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_exit.o)
                0x0001c930                _exit
                0x0001c930                exit
 *(.fini9)
 *(.fini8)
 *(.fini8)
 *(.fini7)
 *(.fini7)
 *(.fini6)
 *(.fini6)
 *(.fini5)
 *(.fini5)
 *(.fini4)
 *(.fini4)
 *(.fini3)
 *(.fini3)
 *(.fini2)
 *(.fini2)
 *(.fini1)
 *(.fini1)
 *(.fini0)
 .fini0         0x0001c930        0x4 c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/avr51\libgcc.a(_exit.o)
 *(.fini0)
                0x0001c934                _etext = .

.data           0x00800100      0x732 load address 0x0001c934
                0x00800100                PROVIDE (__data_start, .)
 *(.data)
 *(.data*)
 .data.comActiveInterface
                0x00800100        0x1 Bootloader/com.o
 .data.timer.3573
                0x00800101        0x4 Bootloader/led.o
 *(.gnu.linkonce.d*)
 *(.rodata)
 .rodata        0x00800105        0x4 Bootloader/flash.o
 *(.rodata*)
 .rodata.str1.1
                0x00800109      0x2a2 backup_hal.o
 .rodata.str1.1
                0x008003ab       0x2a Bootloader/bootloader.o
 .rodata.CSWTCH.10
                0x008003d5        0x3 Bootloader/com.o
 .rodata.str1.1
                0x008003d8       0x41 Bootloader/cpu.o
 .rodata.str1.1
                0x00800419      0x2ec Bootloader/flash.o
                                0x2fe (size before relaxing)
 .rodata.flashLayout
                0x00800705       0x75 Bootloader/flash.o
 .rodata.str1.1
                0x0080077a       0x3e Bootloader/led.o
 .rodata.str1.1
                0x008007b8       0x71 Bootloader/xcp.o
 .rodata.xcpStationId
                0x00800829        0x8 Bootloader/xcp.o
 *(.gnu.linkonce.r*)
                0x00800832                . = ALIGN (0x2)
 *fill*         0x00800831        0x1
                0x00800832                _edata = .
                0x00800832                PROVIDE (__data_end, .)

.bss            0x00800832      0x4ae
                0x00800832                PROVIDE (__bss_start, .)
 *(.bss)
 *(.bss*)
 .bss.backdoorExtensionTime
                0x00800832        0x4 Bootloader/backdoor.o
 .bss.backdoorOpenTime
                0x00800836        0x4 Bootloader/backdoor.o
 .bss.backdoorOpen
                0x0080083a        0x1 Bootloader/backdoor.o
 .bss.timer.3610
                0x0080083b        0x2 Bootloader/can.o
 .bss.timer.3764
                0x0080083d        0x2 Bootloader/flash.o
 .bss.file_length
                0x0080083f        0x4 Bootloader/flash.o
                0x0080083f                file_length
 .bss.idBlockInfo
                0x00800843      0x104 Bootloader/flash.o
 .bss.bootBlockInfo
                0x00800947      0x104 Bootloader/flash.o
 .bss.blockInfo
                0x00800a4b      0x104 Bootloader/flash.o
 .bss.millisecond_counter
                0x00800b4f        0x4 Bootloader/timer.o
 .bss.keyReceivedLen.3743
                0x00800b53        0x1 Bootloader/xcp.o
 .bss.keyBuffer.3739
                0x00800b54       0x40 Bootloader/xcp.o
 .bss.keyCurrentPtr.3742
                0x00800b94        0x2 Bootloader/xcp.o
 .bss.keyTotalLen.3741
                0x00800b96        0x1 Bootloader/xcp.o
 .bss.keyPreviousRemainder.3740
                0x00800b97        0x1 Bootloader/xcp.o
 .bss.seedCurrentPtr.3733
                0x00800b98        0x2 Bootloader/xcp.o
 .bss.seedRemainderLen.3732
                0x00800b9a        0x1 Bootloader/xcp.o
 .bss.seedBuffer.3731
                0x00800b9b       0x40 Bootloader/xcp.o
 .bss.sequenceInProgress.3734
                0x00800bdb        0x1 Bootloader/xcp.o
 .bss.xcpInfo   0x00800bdc       0x4a Bootloader/xcp.o
 .bss.timer0_fract
                0x00800c26        0x1 Drivers/wiring.o
 .bss.timer0_millis
                0x00800c27        0x4 Drivers/wiring.o
                0x00800c27                timer0_millis
 .bss.timer0_overflow_count
                0x00800c2b        0x4 Drivers/wiring.o
                0x00800c2b                timer0_overflow_count
 *(COMMON)
 COMMON         0x00800c2f       0x60 system_states.o
                0x00800c2f                rx_buffer_head
                0x00800c30                rx_buffer_tail
                0x00800c31                tx_buffer_head
                0x00800c32                cbCANFrame
                0x00800c52                RXIDFilterSave
                0x00800c8e                tx_buffer_tail
 COMMON         0x00800c8f       0x51 Drivers/avr_can.o
                0x00800c8f                write_id
                0x00800c93                tx_frame_buff
                0x00800cb7                bigEndian
                0x00800cb8                numTXBoxes
                0x00800cb9                callbacksActive
                0x00800cbb                rx_frame_buff
                0x00800cdf                busSpeed
                0x00800ce0                PROVIDE (__bss_end, .)
                0x0001c934                __data_load_start = LOADADDR (.data)
                0x0001d066                __data_load_end = (__data_load_start + SIZEOF (.data))

.noinit         0x00800ce0        0x0
                [!provide]                PROVIDE (__noinit_start, .)
 *(.noinit*)
                [!provide]                PROVIDE (__noinit_end, .)
                0x00800ce0                _end = .
                0x00800ce0                PROVIDE (__heap_start, .)

.eeprom         0x00810000        0x0
 *(.eeprom*)
                0x00810000                __eeprom_end = .

.fuse
 *(.fuse)
 *(.lfuse)
 *(.hfuse)
 *(.efuse)

.lock
 *(.lock*)

.signature
 *(.signature*)

.user_signatures
 *(.user_signatures*)

.stab
 *(.stab)

.stabstr
 *(.stabstr)

.stab.excl
 *(.stab.excl)

.stab.exclstr
 *(.stab.exclstr)

.stab.index
 *(.stab.index)

.stab.indexstr
 *(.stab.indexstr)

.comment        0x00000000       0x30
 *(.comment)
 .comment       0x00000000       0x30 system_states.o
                                 0x31 (size before relaxing)
 .comment       0x00000030       0x31 backup_hal.o
 .comment       0x00000030       0x31 Bootloader/assert.o
 .comment       0x00000030       0x31 Bootloader/backdoor.o
 .comment       0x00000030       0x31 Bootloader/boot.o
 .comment       0x00000030       0x31 Bootloader/bootloader.o
 .comment       0x00000030       0x31 Bootloader/can.o
 .comment       0x00000030       0x31 Bootloader/com.o
 .comment       0x00000030       0x31 Bootloader/cop.o
 .comment       0x00000030       0x31 Bootloader/cpu.o
 .comment       0x00000030       0x31 Bootloader/cpu_comp.o
 .comment       0x00000030       0x31 Bootloader/flash.o
 .comment       0x00000030       0x31 Bootloader/hooks.o
 .comment       0x00000030       0x31 Bootloader/led.o
 .comment       0x00000030       0x31 Bootloader/nvm.o
 .comment       0x00000030       0x31 Bootloader/timer.o
 .comment       0x00000030       0x31 Bootloader/xcp.o
 .comment       0x00000030       0x31 config_hal.o
 .comment       0x00000030       0x31 Drivers/ASTCanLib.o
 .comment       0x00000030       0x31 Drivers/avr_can.o
 .comment       0x00000030       0x31 Drivers/can_drv.o
 .comment       0x00000030       0x31 Drivers/can_lib.o
 .comment       0x00000030       0x31 Drivers/gpio.o
 .comment       0x00000030       0x31 Drivers/i2c.o
 .comment       0x00000030       0x31 Drivers/uart.o
 .comment       0x00000030       0x31 Drivers/wiring.o

.note.gnu.avr.deviceinfo
                0x00000000       0x40
 .note.gnu.avr.deviceinfo
                0x00000000       0x40 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o

.note.gnu.build-id
 *(.note.gnu.build-id)

.debug
 *(.debug)

.line
 *(.line)

.debug_srcinfo
 *(.debug_srcinfo)

.debug_sfnames
 *(.debug_sfnames)

.debug_aranges
 *(.debug_aranges)

.debug_pubnames
 *(.debug_pubnames)

.debug_info     0x00000000      0xa2d
 *(.debug_info .gnu.linkonce.wi.*)
 .debug_info    0x00000000      0xa2d C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o

.debug_abbrev   0x00000000      0x9a0
 *(.debug_abbrev)
 .debug_abbrev  0x00000000      0x9a0 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o

.debug_line     0x00000000      0x175
 *(.debug_line .debug_line.* .debug_line_end)
 .debug_line    0x00000000      0x175 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o

.debug_frame
 *(.debug_frame)

.debug_str      0x00000000      0x39f
 *(.debug_str)
 .debug_str     0x00000000      0x39f C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o

.debug_loc
 *(.debug_loc)

.debug_macinfo
 *(.debug_macinfo)

.debug_weaknames
 *(.debug_weaknames)

.debug_funcnames
 *(.debug_funcnames)

.debug_typenames
 *(.debug_typenames)

.debug_varnames
 *(.debug_varnames)

.debug_pubtypes
 *(.debug_pubtypes)

.debug_ranges
 *(.debug_ranges)

.debug_macro
 *(.debug_macro)
OUTPUT(BMS.elf elf32-avr)
LOAD linker stubs

.bootloader     0x0001e000      0x882
 .bootloader    0x0001e000       0x8e Bootloader/bootloader.o
                0x0001e000                main
 .bootloader    0x0001e08e      0x7f4 Bootloader/flash.o
                0x0001e4a8                FlashReinit
                0x0001e4e0                FlashInit
                0x0001e4e2                FlashWrite
                0x0001e5c6                FlashWriteChecksum
                0x0001e670                FlashVerifyChecksum
                0x0001e7f8                FlashDone

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On reset, the avr jumps to 0x1E000 which is the start of the bootloader section set by the fuses. Your vector table is at 0x1A000, which is where your reset vector is located (you are only using the first vector- the reset vector). To get to your bootloader which is below the bootloader section, you will have to make your own jump to your bootloader from the hardware reset address 0x1E000.

 

Maybe something like this, where you carve out a word to do the jump-

.bootloader_vector = 0xF000

.bootloader = 0xF001

 

then create a function to jump to your bootloader reset vector-

__attribute(( section(".bootloader_vector") )) void blreset(){ asm("jmp 0x1A000"); }

 

So on reset- program counter = 0x1E000, jmp 0x1A000, now at your bootloader reset vector which proceeds as normal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AmVRosia wrote:
If a firmware transfer takes place, then after every reboot the AVR always jumps to the application section and runs the application firmware.
First guess is an uniniitialized variable; second guess is bootloaders are typically built without the C standard initializers (static, auto)

Third guess is CRC or checksum computed value is incorrect, or, simple defect in a conditional.

Try passing the bootloader's source code through a few or several linters; correct the identified defects, re-build, then re-try.

If no joy then sprinkle assertions.

AmVRosia wrote:
I have the impression that once in a while it stucks for a minute without responding after reboot and then recovers and starts the application.
Bitten by the watchdog? (infinite loop?)

AmVRosia wrote:
If during file transfer there is power loss ... the AVR gets briked and in order to work again it has to be re flashed via the programmer.
BOD enabled?

AmVRosia wrote:
... or CANBus cable removal, ...
indecision

State machine defect?

AmVRosia wrote:
The hardware reset does not work.
Fundamental defect

 


Adding Automatic Debugging to Firmware for Embedded Systems by Jack Ganssle

 

Connection of RESET Pin on AVR Devices | AVR® Microcontroller Hardware Design Considerations (AVR042)

External RESET Switch | AVR® Microcontroller Hardware Design Considerations

 

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1


curtvm wrote:

On reset, the avr jumps to 0x1E000 which is the start of the bootloader section set by the fuses. Your vector table is at 0x1A000, which is where your reset vector is located (you are only using the first vector- the reset vector). To get to your bootloader which is below the bootloader section, you will have to make your own jump to your bootloader from the hardware reset address 0x1E000.

 

Maybe something like this, where you carve out a word to do the jump-

.bootloader_vector = 0xF000

.bootloader = 0xF001

 

then create a function to jump to your bootloader reset vector-

__attribute(( section(".bootloader_vector") )) void blreset(){ asm("jmp 0x1A000"); }

 

So on reset- program counter = 0x1E000, jmp 0x1A000, now at your bootloader reset vector which proceeds as normal.

 

Thank you. Ok I understand the above and I tried that. Unfortunatelly I still get similar response. It seems like if there is something in address 0 (the application) it always jumps there after reboot. 

I was wondering if the optimisation or garbage collector remove the blreset() funtion from the flash because its size looks like zero.

 


text           0x0001a000     0x29d2
 *(.vectors)
 .vectors       0x0001a000       0x94 C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.3.300/gcc/dev/at90can128/avr51/crtat90can128.o
                0x0001a000                __vector_default
                0x0001a000                __vectors
 *(.vectors)



...

...




.bootloader_vector
                0x0001e000        0x0

.bootloader     0x0001e002      0x7f4
 .bootloader    0x0001e002      0x7f4 Bootloader/flash.o
                0x0001e41c                FlashReinit
                0x0001e454                FlashInit
                0x0001e456                FlashWrite
                0x0001e53a                FlashWriteChecksum
                0x0001e5e4                FlashVerifyChecksum
                0x0001e76c                FlashDone

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gchapman wrote:

First guess is an uniniitialized variable; second guess is bootloaders are typically built without the C standard initializers (static, auto)

Third guess is CRC or checksum computed value is incorrect, or, simple defect in a conditional.

Try passing the bootloader's source code through a few or several linters; correct the identified defects, re-build, then re-try.

If no joy then sprinkle assertions.

I am not really following the 3 guesses :-D

 

There are warnings in the project if I increase the warning level in project settings.

 

Is there any freewhere linter?
 

 

gchapman wrote:

Bitten by the watchdog? (infinite loop?)

 

I do not use the watchdog yet because I have not fixed the reset issue and the program counter might end up anywhere.

 

 

gchapman wrote:

 

BOD enabled?

Nope. I simulate those problems by turning off the power supply etc while it is transfering the firmware. It has to be in a position to recover (it is good enough if it jumps back to the bootloader).

 

 

gchapman wrote:

State machine defect?

Which state machine?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AmVRosia wrote:
Is there any freewhere linter?
FOSS and alternatives, and, yes.

The ones at Microchip Technology recognized the EoS of PC-lint then created a linter plug-in for MPLAB X; PC-lint Plus demo is excellent for source code snippets.

An excellent file-scope linter is in Visual Studio (reduced scope lint is usually enough)

AmVRosia wrote:
I simulate those problems by turning off the power supply etc while it is transfering the firmware.
Glitching VCC is one way to cause AVR anomalies with one avenue via the NVM controller.

AmVRosia wrote:
Which state machine?
One way to create a preliminary design for a bootloader is by hierarchical finite state machines.

IIRC, the ISO C standard mentions an abstract state machine (context is static analysis)

 


Come Join Us (MPLAB Now Supports AVRs) | Page 8 | AVR Freaks; IIRC, MPLAB X linter is an instance of Cppcheck - A tool for static C/C++ code analysis

PC-lint Plus Online Demo - Gimpel Software - The Leader in Static Analysis for C and C++ with PC-lint Plus

/analyze (Code analysis) | Microsoft Docs

Visual Studio extension | SonarLint (SonarSource)

 

ATmega128/L Datasheet

[page 282]

Preventing Flash Corruption

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My mistake- a jmp is 2 words so need to allow more room-

.bootloader_vector = 0xF000

.bootloader = 0xF002

or if doing some other way to jump to your bootloader, then allow enough room for the instructions (not quite sure why you want an ijmp instead of a jmp).

Last Edited: Tue. May 17, 2022 - 12:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


 

curtvm wrote:

My mistake- a jmp is 2 words so need to allow more room-

.bootloader_vector = 0xF000

.bootloader = 0xF002

or if doing some other way to jump to your bootloader, then allow enough room for the instructions (not quite sure why you want an ijmp instead of a jmp).

 

The jmp does not seem to work. The ijmp seems to perform the jump. Is it because I am working on the highest end of addresses?

 

The instruction size for the ijmp seems to be 5 words (as seen in the .map file too). Anything smaller than that returns the error that the sectors are overlaping.

 

It seems that the garbage collector removes the instruction from memory. I solved the problem but I am sure there will be a cleaner way. Now no matter if there is an application, after reboot the bootloader is always executed. I used a dummy volatile variable "force_vector_in_memory" to force the ijmp to stay in the flash:

 

 

 

Is there a better way to do this with a gcc instruction?

 

Last Edited: Tue. May 17, 2022 - 05:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another mistake I made- the function is not naked so a ret instruction is added (thus 6 bytes).

 

A problem will be that the linker will want to discard the jmp function, and getting it to not discard it is bit of a problem.

 

 

I would head in the direction of just copying the linker scrip to the local project folder (avr51.xn). You can then get things the way you want without all the section address options from the command line.

 

in avr51.xn, change/add to look like this

 

MEMORY
{
  text   (rx)   :
ORIGIN = 0x1A000, LENGTH = 16k
  bootloader_vector (rx) : ORIGIN = 0x1E000, LENGTH = 4
  bootloader (rx) : ORIGIN = 0x1E004, LENGTH = 4092

 

this takes care of where .text starts and its size, where the bootloader_vector starts/size, and bootloader.

 

somewhere in the same file, under SECTIONS, add this-

 

  .bootloader_vector  :
  {
    KEEP(*(.bootloader_vector*))
  }  > bootloader_vector
  .bootloader  :
  {
    KEEP(*(.bootloader*))
  }  > bootloader

 

the KEEP will prevent the linker from discarding the code.

 

 

test code-

 

__attribute(( section(".bootloader_vector"), naked )) void blreset(){ asm("jmp 0x1A000"); }
__attribute(( section(".bootloader") )) char some_bootloader_code(){ return 1; }
int main(void) {
    while (1) {}
}

 

get rid of all the previous command line address info, add this linker option to use your own linker script-

-Wl,-T avr51.xn

 

result-

 

Disassembly of section .text:

0001a000 <__vectors>:
   1a000:    0c 94 4a d0     jmp    0x1a094    ; 0x1a094 <__ctors_end>
   1a004:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a008:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a00c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a010:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a014:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a018:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a01c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a020:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a024:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a028:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a02c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a030:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a034:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a038:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a03c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a040:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a044:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a048:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a04c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a050:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a054:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a058:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a05c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a060:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a064:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a068:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a06c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a070:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a074:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a078:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a07c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a080:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a084:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a088:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a08c:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>
   1a090:    0c 94 54 d0     jmp    0x1a0a8    ; 0x1a0a8 <__bad_interrupt>

0001a094 <__ctors_end>:
   1a094:    11 24           eor    r1, r1
   1a096:    1f be           out    0x3f, r1    ; 63
   1a098:    cf ef           ldi    r28, 0xFF    ; 255
   1a09a:    d0 e1           ldi    r29, 0x10    ; 16
   1a09c:    de bf           out    0x3e, r29    ; 62
   1a09e:    cd bf           out    0x3d, r28    ; 61
   1a0a0:    0e 94 56 d0     call    0x1a0ac    ; 0x1a0ac <main>
   1a0a4:    0c 94 57 d0     jmp    0x1a0ae    ; 0x1a0ae <_exit>

0001a0a8 <__bad_interrupt>:
   1a0a8:    0c 94 00 d0     jmp    0x1a000    ; 0x1a000 <__vectors>

0001a0ac <main>:
   1a0ac:    ff cf           rjmp    .-2          ; 0x1a0ac <main>

0001a0ae <_exit>:
   1a0ae:    f8 94           cli

0001a0b0 <__stop_program>:
   1a0b0:    ff cf           rjmp    .-2          ; 0x1a0b0 <__stop_program>

Disassembly of section .bootloader_vector:

0001e000 <blreset>:
   
1e000:    0c 94 00 d0     jmp    0x1a000    ; 0x1a000 <__vectors>

Disassembly of section .bootloader:

0001e004 <some_bootloader_code>:
   1e004:    81 e0           ldi    r24, 0x01    ; 1
   1e006:    08 95           ret

 

 

avr reset- 0x1e000, jmp 0x1a000, now normal boot

Last Edited: Tue. May 17, 2022 - 07:45 PM

Pages