Orange Pi
|
Yes, that would be the best way of doing it.
You seem to have misunderstood what exclusive means :-) block1 start: &10000000 block1 end: &20000000 block2 start: &20000000 blah blah. If you were to pass in &1FFFFFFC then the kernel would round it down to the next page boundary (so &1FFFF000), but should otherwise work fine
Technically the HAL should have no workspace, until the kernel gives it an address to use via HAL_Init. If the HAL needs workspace prior to calling OS_Start, then it’s the HAL’s responsibility to find a safe place to store it (e.g. SRAM). If we had a way of checking memory access during startup then it would be possible to come up with a concrete specification of how the kernel/HAL should handle memory leading up to HAL_Init, and then run some automated tests to make sure all the different edge cases are dealt with correctly. |
|
Did you mean ethereal or ephemeral? |
|
Steve, I have contemplated this and believe ethereal was a better fit. Jeffrey, are you referring to clobbering the stack ingeneral? I’m just checking because I’m resetting the stack before OS_Start anyway because I can’t think of any good reason to preserve anything that may be in there, not that there really should be AFAIK
Do you mean the stack, or SRAM? Both actually seem like interesting ideas.
Clearly! My understanding wasn’t wrong. Just incorrect in this context. It’s why I asked. Michael, I have to get that far first! I haven’t even been able to look at it. Too busy. Breaks are good though. It gives time to think things over properly. |
|
Just for the period prior to OS_Start. Although, now that I think about it, the only places where OS_AddRAM writes to memory are (a) the stack and (b) the start of the first memory block (so it can build up a list of all the blocks). So as long as you don’t set the stack pointer to be within, say, the first 1K of the first memory block you should be fine.
SRAM. Passing information over OS_Start via the stack won’t do you any good because the kernel sets up its own stacks (and may wipe or overwrite whatever stack you were originally using, if it was in an area of RAM registered via OS_AddRAM) |
|
I have some fixing to do before continuing. Yesterday I had some time to work on my code. After doing some fixing there was a build error in my HAL code that I had to do more and more work to make go away. I swapped out the Pi Zero for the Pi 3. I haven’t been using it because fo heat issues. I’ve found a way to drop the temperature a bit but that’s something for another thread. This brings me to now. I need clarification… again. Sorry Jeffrey. In the HAL documentation, OS_InitARM is 0, and OS_AddRAM is 1 in the order of RISC OS Entry points by number. OS_AddRAM states that it must be the first call to RISC OS after a hardware reset. Which one am I meant to call first? e: fixed the broken bit stopping the code from getting to where it normally does. Back to staring at the HAL.s source trying to understand why that bit gets stuck. |
|
That would suggest either (a) a bug in the kernel that’s triggered by certain memory configurations passed to OS_AddRAM, or (b) your HAL is corrupting the RAM list (or passing a bad pointer)
OS_InitARM first. I’ve updated the wiki docs for OS_AddRAM to be more accurate. |
|
Thanks again! I forced the kernel HAL.s to progress past that point. Obviously it broke further along, but I wanted to see where it broke. It definitely points to an issue in the way I’m giving RISCOS_AddRAM its data. I’m just setting up my code to do a dumb copy of the OS Image so I can apply different RAM organization. Trouble is, it’ll be putting the OS within the U-Boot declared VRAM. I haven’t worked out how to shift it yet. At least it’ll be in a high area which hopefully won’t get touched. I’m leaving the SRAM alone for now. I’m pretty sure the CPU vector table lives at 0×0 still. Unrelated, but when I wanted to dig for memory mapping in Linux on the OPi PC, I accidentally put in an SD card for the OPi Zero (H2+). It booted fine, so I just used it for my hunt. Hopefully shifting the RO image above everything will get around the memory mapping issue as I know you suggested previously. The only reason I haven’t done it yet is it pretty much clobbers everything so I have to tread carefully. |
|
I moved it up to 0×42000000, and just gave it a single block of the memory in 0×40000000 to 0×42000000 below it. I figure it should be enough to give me insight into if it is the position of the image in memory that’s the issue. While kind of awful, is there anything inherently wrong with this for a heavily reduced test of adding RAM and going into RISCOS_Start?
|
|
Yes. With APCS, only a1-a4 are used to pass arguments to functions. Any extra arguments (i.e. v1) must be pushed onto the stack. So you need to change from this: MOV v1, #0 CallOSM OS_AddRAM To something like this: MOV temp, #0 PUSH {temp} ; or whatever other stack push macro/instruction you prefer CallOSM OS_AddRAM ADD sp,sp,#4 ; it's the caller's responsibility to clear the extra arguments off of the stack after the function call Note that the OMAP3 HAL cheats a bit and doesn’t bother clearing the argument off the stack – since it knows there’s only a max of 2 RAM blocks and that OS_Start is going to reset the stack anyway. For now, I’d also avoid setting bit 4 of a1 when calling OS_Start, because the kernel does use that flag to make assumptions about whether some areas of workspace have been zero-initialised or not. (there’s also a bit of a grey area with respect to wiping the stack and the RAM block list, since I don’t think those are explicitly cleared anywhere. So if you’re very unlucky you might encounter an issue due to that) |
|
It didn’t even occur to me that OS_AddRAM was APCS compliant, even though I think you may have told me that ages ago. Sorry! After fixing the param passing blunder it goes in RISCOS_Start and out the other end. My HAL_Init pretty much just consists of a debug character. |
|
If there’s no fast DMA to clear the RAM, it’s better to let the kernel do it, since it can do it pretty quickly (and it’ll be able to do it in parallel to the keyboard scan that’s used to control CMOS reset, etc.)
Hurrah! From what you said on the last page I guess I should be seeing something besides just that? Yes, the next thing you see after that should be a “HAL initialised” message that’s output by the kernel, via HAL_DebugTX. https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/HAL?rev=4.9#l1018 |
|
Sorry. I’ve been super busy. Sadly I was wrong about how far the code was getting. The hazards of copy-pasting code blocks. The prerequisites for even getting that far seem to be to only have mapped RAM below the RO image. Not sure if the number of blocks makes a difference. I have a couple of questions. 1: The addresses mentioned in the HAL make file and env(?) file which start in &FCxxxxxx for the ROM location. Given the address I would assume that is a Post-MMU logical address. Is that correct? 2: I can’t seem to easilt do anything about the location of the VRAM &7FE79000 – &7FFF1E00 which is nearly to the top of RAM on my test machine. The little bit above is the U-Boot stack. Do I omit this from the mapping, or add it as VRAM? Trouble being everything seems to collapse in a heap if I declare any RAM above the OS image. |
|
One thing to remember is that once the MMU is turned on, any debug code you’ve added to the kernel which writes to the physical address of the UART won’t work, because it won’t be mapped into the logical address space yet. So if you have debug code located after that point, you’ll either have to remove it, or add some code to make sure the UART gets mapped in.
Correct.
Keep things simple and omit it from the mapping.
|
|
As always, useful information. Moving along slowly but surely. Lots of missing, broken, and hardcoded bits. Also a healthy dose of Cargo Cult programming but I’m slowly working out what things do in the source. I’m using both OMAP3 and BCM2835 code as reference. They both have very different ways of going about the same tasks. This makes it possible to extrapolate what’s actually going on. I just saw proof that my recent ROM relocation code isn’t quite working right. I didn’t think it would. It’s too simple.
|
|
Turn on the debug terminal (DebugTerminal option in Kernel.hdr.Options) and you should see something much more exciting :-) |
|
It locks up part way through loading! Haha I don’t think that’s what you mean though. Really I’m surprised it gets as far as it does.
The good thing about describing things like this is I found a mistake in my relocation code. It doesn’t invalidate caches, check MMU is off etc until after relocation. Whoops! |
|
Which is surprising, if you’re basing your work off of the OMAP3 and BCM HALs :-) Providing you can work out the register usage, you should be able to use the existing code as-is (just make sure you use the ARMv7 cache maintenance ops from the OMAP3 HAL, not the ARMv6-ish ones from the BCM HAL)
If you had some code like this for transmitting a byte: LDR a2, =UART_Phys ; physical address of UART registers STRB a1, [a2, #UART_TX] Then the simple way of converting that to use logical addresses would be: ; In HAL_Init MOV a1, #0 LDR a2, =UART_Phys MOV a3, #UART_Size CallOS OS_MapInIO STR a1, UART_Log ; where UART_Log is in the HAL static workspace ; In HAL_DebugTX LDR a2, UART_Log STRB a1, [a2, #UART_TX] The complexity in the current HALs is that they try to minimise the number of times OS_MapInIO is called. They know that the hardware registers for all the different peripherals tend to be located near to each other in physical space, so they just make one or two calls to OS_MapInIO in order to map in one or two large blocks, and then manually calculate the offsets for the different peripherals within those blocks. But in practical terms there’s little difference between the two approaches. Also there’s complexity in the OMAP3 HAL due to the way that it’s designed to work work with many different boards, each with its own UART mapping. |
|
You answered a question that I forgot to ask! About mapping large blocks of IO vs small ones. Given the memory layout it is vastly preferable for me to do a couple of large blocks.
Yeah. no. The thing about that is OMAP3 Top.s is dripping with macro-nese. My version has been written from scratch and is very rickety. Pretty much feeling my way and seeing what works. On the positive side I tried to keep the HAL code structure roughly similar to OMAP3 where I could. I’m going to put aside my version of Top.s and try to use a stripped version of the OMAP3 Top.s as a skeleton. All the board config macro things and the simulated Linux header things were getting in the way. And I kind of tended towards the BCM code whenever I came across anything to do with interconnects in the OMAP code. From what I can tell, the Kernel should be fine, so long as I can work out how to feed it what it wants. I’m not looking forward to dealing with the interrupts. The GIC is well documented, but I don’t think any other RO ports use it. |
|
You saw output past HAL_Init. I had no problem mapping in IO. What I’m not as sure of is how to store things effectively in the workspace post HAL_Init. Correct.
I incorrectly assumed that you already understood that part :-) ObjAsm is able to automatically translate things like “ https://www.riscosopen.org/wiki/documentation/show/A%20BASIC%20guide%20to%20ObjAsm%20Part%203 (see the “base register” section)
Hint: The ROM relocation code starts at the relocate_code label and ends at the “Copy completed OK” comment. Strip out the DMA code and you’ll be left with something that’s practically identical to the relocation code that’s present in the BCM HAL (since I just copied & pasted the code, since there’s no point reinventing the wheel)
OMAP4, OMAP5, Titanium, iMX6 all use the GIC (although not all the same version, and probably using SoC-specific register names rather than ARM’s official ones) |
|
That link was exactly what I needed. Thanks. I was a little uncertain on how to apply offsets to entries so I could do things like populate the UART base address entries using that method. The Interrupt controller is a GIC PL400. Putting there for me too. I just had to find it in the datasheet again because I’m not sure where I saved the GIC datasheet. The hazard of working from multiple devices. |
|
The processor vectors should be set up somewhere around the “IMB_Full” debug print, so if the machine was crashing with a data abort or similar I’d expect you to see some debug output from that. Which suggests that it hasn’t crashed, and instead it’s just stuck in a loop somewhere – possibly due to the timers not being implemented (unlikely, AFAIK it should initialise at least one or two modules before reaching anything timer-dependent), or possibly due to an interrupt firing (there’s a good chance one of u-boot’s hardware drivers left an interrupt or two enabled). Without having any interrupt code in the HAL there’s no way for the OS to mask the errant interrupt, so it just gets stuck in an infinite loop constantly being pulled back into the interrupt processor vector. So I’d try implementing some basic handling of the GIC. Possibly you could lift most of the code from another HAL, but the problem there is that all the current GIC drivers are a bit quirky so you’ll either have a hard time understanding what’s going on, or you’ll just be proliferating those quirks. The code in the Titanium HAL is probably the cleanest, you just need to strip out the code for handling the PCI interrupts. Once you’ve got something up and running, it might be worth adding some debug output (e.g. to HAL_IRQSource) just so you can make sure the code is working correctly and the system isn’t stuck in an interrupt loop (in fact, adding some code to your current empty HAL_IRQSource would be a good way of verifying that an errant interrupt is the cause of the current problem) |
|
Stepping in here… I don’t think I have a working interrupt HAL (as in not completely fully functional) and I get to the debug prompt without workarounds. |
|
I’m really not sure what’s happening with it yet. I’m going back through and making some bits less skeletal. Un-commenting or un-short circuiting some debug sections etc. to bring it closer to what it should be. With HAL debug enabled it gets as far as InitDynamicAreas so that’s a step back. Without debug, I have no idea. I fixed debug output so it doesn’t output anything. Didn’t think that through. I changed MapInIO to just map in a big block, and I started work on extrapolating from that. Previously the only thing I had mapped in was the UARTs. I did some reading. Apparently U-Boot doesn’t use interrupts. It’s single threading and polling. I really wish I could easily share my code to get some more eyes on it, but RO doesn’t lend itself easily to that. Next time I’m at the computer I’ll add some output code to the Interrupt stuff too see if anything there is firing. |
|
Hey, look!
It was a second attempt boot. First time around it reset somewhere between MMU init and HAL init. I tried another load and run which got it that far. |
|
RTSupport doesn’t work for me, try to leave that out. |