It is the 1727th of March 2020 (aka the 21st of November 2024)
You are 3.147.68.201,
pleased to meet you!
mailto:blog-at-heyrick-dot-eu
ROOL forums and off-topic posts
Just a quick note - I am likely to be a little less helpful around there. This is because I had seen the forums as a place not only for help and assistance with RISC OS and related matters, but also with the "Aldershot" forum for non-RISC OS related stuff, to discuss random things with people who were reasonably intelligent and held similar interests. Recently, it was brought to everybody's attention that such "off topic" content is too difficult for some people to skip over (as if everything else posted is always of great interest to everybody - some things are specific to certain problems or situations and just won't apply to others; if one can skip that, why not other stuff of no interest?). When I pointed this out, the reply was that I was the major creator of off-topic content. Okay, point made. I'll give up participating in the off-topic stuff, as I very much doubt anybody is going to tweak the forum code to display Recent Posts with and without it (for those who don't want).
Now me saying I'm going to be less helpful is not me in a strop or sulking. It is a natural consequence of if I'm going to consider the forum from now on purely as a place for help and assistance regarding RISC OS, then I don't really need that much help, so I will only be visiting the forum once or twice a day, if that. Instead of once or twice an hour when I wasn't otherwise occupied (yeah, I know, sad...).
Funnily enough, in the ~week I've cut back on participation, I suddenly find I have more time free to do other things. ☺
It is worth noting that David Boddie said (in a topic that was not only off-topic itself, but went on longer than the Islamophobia topic that triggered it):
For example, there may well have been people who joined the discussion about Brexit with the idea that, because they share similar computing preferences to the others in the forum, they would agree on that topic as well. As a result of that discussion, perhaps they don’t feel like participating here so much.
The two obvious points to raise are firstly that Brexit is going to have a huge impact on the United Kingdom. Not one single day goes by that something to do with it is mentioned in the news. Plus, the winning result was slightly over half, which means slightly under half are opposed to this, and I think anybody with a brain should be opposed to the shambolic way negotiations are being handled. Pretending Brexit doesn't exist won't cause it to go away, and I'd rather discuss aspects of it with intelligent people than those who are going to shout down every plausible problem with it by quoting their choice selection of mantra. Yes, there are other places to talk about it. But if you look at the sorts of comments you get in the Daily Mail, Express, etc - there are not so many places where anybody is even remotely interested in discussing it in a proper adult manner.
Secondly, it is rather childish of a person to assume that "because you like X, you'll like Y as well". I know one of the forum members is Big On Beer (not as in drinking, as in appreciating its qualities). I hate the stuff. I wrote the code below to a selection of Nightwish, Within Temptation and Kalafina (yes, really). Some people might me "oh my God, learn to enjoy Radio Two". We all have something in common, which is good, but it is ridiculous to expect other people to be facsimiles of ourselves.
I liked the forums because the average member wasn't a halfwit. Wander into Usenet, you'll meet plenty of people who would struggle to quality as even a quarterwit. Fancy trying to discuss something reasonable with them? No thanks.
The thing is, though, that the indirect chilling effect of frowning on off-topic messages has had a negative effect on the forums. In a topic about Omniclient, Chris Mahoney was asking about whether or not Omni can deal with NFS shares. It seems that Sunfish could do it but was a bit crashy. He ended with:
It’s better than it was, but is still crashing frequently. But this isn’t a Sunfish thread so I’ll leave it for now!
He didn't start a new thread. Now the problem here is that while Chris was indeed posting to a thread entitled "An idiot's guide to OmniClient", he had a very specific requirement that he wanted to achieve - to get his RISC OS machine talking to an NFS share. If Omni isn't up to it, then obviously the thread is going to deviate to alternative options. And if the alternative is crash-prone, is it so bad to see if there is anything that could help? For all we know, it could be a simple setting - maybe something obscure like the ShareFSWindow trick. Instead, continuing was deemed "off topic" and the discussion ended. Chris is probably still using a crashy Sunfish, his problem wasn't properly resolved, and if anybody else has a similar need, there's only half an answer to point them at...
Well, I guess I should have posted this to the forum...but it would have been off-topic...
ARGH! WE'RE ALL GOING TO DIE! ARGH!
In a topic on Aldershot (that I didn't participate in because...), Xavier Louis Tardy said:
I prefer to play ‘Doctor Doom’ and bring this info, even if not that serious, than keeping it for myself and hear later on that you have suffered from my keeping it for myself, so please read this :
http://enenews.com/fears-of-a-major-nuclear-accident-reuters-radioactivity-levels-surged-to-1000-times-normal-in-russia-ap-extremely-high -contamination-concerns-over-govt-cover-up
Which is fair enough, and it has already been covered in the press (anomalous radiation readings and nobody knows why). My own thought at the time was to wonder if the Chernobyl sarcophagus had failed.
He then continued:
I do not think I need to tell you not to eat anything fresh growing in the air, and no mushrooms, sage, thym, whatever and no milk ...
and staying inside, closing all ventilations too, could be not that stupid after all.
The youngest the weakest, as you know with cell replications.
Which is just scare-mongering. Our ability to detect radiation means that we can easily detect that which will have less of a health impact than sleeping in a house built of granite. That isn't to say there is no danger - however it must be borne in mind that quite a few of the nuclear tests that took place in Nevada in the latter half of the last century were specifically conducted so that the radioactive cloud would dump its isotopes in eastern Nevada, all over Utah, into Idaho, Oregon, and Washington. Why? To measure and understand the effects of radiation on the populace. You gotta love the US government's pragmatic "screw you" approach to the well-being of its citizens. And yes, isotopes were found in food, bodies, and birth defects happened as well. Some of them bad enough (estimated 10,000-75,000 cases of thyroid cancer and potentially 2,000 cases of leukaemia) to led to an eventual ban on such testing. After 41 years, 100 above ground detonations, and 921 underground (venting to the exterior) detonations. After all of that, the Nevada site is a radioactive wasteland, but Utah is still inhabited, as are many places downwind of the test site. Around the same time frame, the Russian site at Novaya Zemlya was host to around 130 tests, including the above-ground detonation of the Tsar Bomba, stepped back from its theoretical 100MT yield to a mere 50MT yield. It pretty much destroyed everything in a 100km radius of the detonation site - the mushroom cloud reached 64km (~40 miles) high, with a width of around 95km (~60 miles) and a base of 40km (~25 miles). To give an idea of the power of this bomb, a thermal pulse was observed at a distance of 270km (~170 miles), an air shock wave was observed 700km (~430 miles) away, and windows were broken a staggering 900km (560 miles) away. Despite a detonation of approximately 4km up, and the cushioning effect of the bombs own blast wave being reflected back at itself, the seismic effects registered a little over 5, and sensors continued reporting the shock waves for three trips around the world. As you can imagine, that detonation in 1961 dumped radiation across the northern hemisphere.
Consequently, the radiation that is in existence today, while not exactly an encouraging thing, is a far cry from the '50s and '60s when both sides of the Cold War were actively detonating nuclear weapons above ground.
As to the second quote of Xavier, I think we have a lot more to fear from fresh produce being sprayed by Imidazole compounds (mould retardant), synthetic weedkillers that were ultimately derived from variations of Agent Orange, washed with unclean (faeces contaminated) water...
Milk? Shall we discuss the antibiotics? Shall we discuss the hormones given to cows to keep them producing milk? If you have a wife or girlfriend, are her breasts full of milk? Probably not, it's a thing called lactation and it happens so animals (from cats to humans) can nourish their young. Human females lactate after giving birth. Well, it's the same with cows. Only since cow milk is useful to humans, humans have found ways of ensuring that the cows always have full udders.
Closing all ventilation in a modern home is not smart. Too many plastics and other synthetic materials.
Better advice? Keep an eye on the story in case it turns out to be terrorists bringing in materials to set off a dirty bomb in some European capital, otherwise continue pretty much as before.
And eat organically produced food...
FirmwareID
A little while back, on the RISC OS forum, I posted a small program to identify RISC OS ROM images. It was in response to a question regarding how to ID the various images.
We are greatly helped in this endeavour by the fact that the core kernel (the 'hidden' "RISC OS" module) is never compressed, so we don't need to mess around with decompressing the ROM or reading an information block which may or may not be present. We simply perform some rudimentary pattern matching to identify what machine the particular ROM is for, then some more pattern matching to find the RISC OS module to extract the version and the build date.
The source code, with comments, runs to about 30K. The program built from it is a compact 2208 bytes, a little over 2K.
Stylistic notes:
I have 156 characters across my screen. I will be using ~100-125 (or so) rather than restricting myself to ~76 characters just in case somebody somewhere is using a VT100 terminal or an fx80 printer. It's 2017, time to embrace the bigger displays we've had for a decade or so...
Indents are three spaces, no tabs.
Braces are placed on separate lines, with the inner code indented. Same-line braces are evil.
Oh, wait... This one is written in assembler! Well, that doesn't matter, if it was C, the above two points would apply. Always and forever. ;-)
PS: B is a GOTO and BL is a GOSUB and since we're this low level, there are no friendly inherited anthropomorphised functions to use. It's hardcore machine code all the way, baby!
Okay then, let's get on with it!
As always, we begin with comments describing the program, what it does, how to use it, and the licence that applies to the source. In this case, the program is open source, released under the CDDL - which is like the famous GPL, only proper "open".
; FirmwareID v0.02; ==========;; Little program to identify a RISC OS firmware.;; Syntax: FirmwareID ;;; CDDL HEADER START;; The contents of this file are subject to the terms of the Common Development and Distribution License (the "Licence").; You may not use this file except in compliance with the Licence.;; You can obtain a copy of the licence at:; https://www.riscosopen.org/viewer/view/~checkout~/cddl/RiscOS/Sources/FileSys/SDFS/SDFS/LICENCE?rev=1.1.1.1; See the Licence for the specific language governing permissions and limitations under the Licence.;; When distributing Covered Code, include this CDDL HEADER in each file and include the Licence file. If applicable, add the; following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information:; Portions Copyright [yyyy] [name of copyright owner];; CDDL HEADER END;; Copyright 2017 Richard Murray. All rights reserved.; Use is subject to license terms.;
The next thing to set up is the AREA name (required for applications that are to be linked, and no, the XX-McXXface joke isn't going to die away just yet.
Then we call in the SWI name definitions file. This is copy-pasted from the one supplied with the DDE, you'll find it (in DDE28) at ...Sources.DDE-Examples.ObjAsm.AsmHdrs.h.SWINames.
If you don't have the DDE and want to try building this with GCC or Nick Roberts' assembler, you can use the SWI definitions that I built for DeskLib32. Pick up a copy here. It is not directly compatible. Every SWI name is prefixed by "SWI_" and there are no X-form SWIs, you need to add the "XOS_Bit" to the number. For instance "XOS_File" would become "(SWI_OS_File + XOS_Bit)". But it's better than nothering if you don't have a list of SWI definitions to hand...
AREA |codey$mccodeface|, CODE, A32bit; no, that joke isn't going to go away...GET ^.h.swinames
Next, define some values. We set up TRUE and FALSE, then number the detected devices, and the vector state. Finally, we give names to registers R9 through R12, which hold global state.
; Define that which is truth and that which is fake newsTRUE * 1FALSE * 0; I was tempted to call this one "BREXIT" or "TRUMP" or something; Detected buildsUNKNOWN * 0IOMD * 1IYONIX * 2OMAP3 * 3OMAP4 * 4TITANIC * 5; Titanium didn't fit, Titanic did ;-)PI * 6PIPICO * 7; Detected vector placementVECIRLV * 0; Means CP15 instruction not found, so vector stuff irrelevant on this machineVECLOW * 1; Low vector (old-style) OSVECHIGH * 2; High vector (new-fangled) OS; Global register allocationsWrkEnd RN 9; Pointer to END of workspaceWrkPtr RN 10; Pointer into workspace (64K) [note: NOT pointer TO workspace!]FlSize RN 11; File size (for Pico detection)FlName RN 12; Pointer to filename (from OS_GetEnv, READ ONLY)
Now we're on to the program proper. ENTRY tells the linker where the program starts (as it automatically adds a valid AIF header for us).
The next section of code looks at how much memory we have. If our program is a little over 2K, we use a 64K buffer, and some stack space, we will request 72K (perhaps 68K would be enough, but it's better to err on the side of caution).
One complication is that the OS_GetEnv returns our memory limit. That is to say, the physical location of the end of our available memory. This is a complication as every application starts at the address &8000, not at zero, so the value will be 32K larger than the actual amount of memory available. The addressing range from zero to 32K is traditionally used for system workspace and various buffers and stuff, however on a high vector ROM build, there just won't be anything there. Essentially, the first 32K is off limits to applications.
If there isn't enough memory, we call the Wimp_SlotSize command to give ourselves 72K. If this fails (no memory or Wimp not present (as in Pico)), we bail out. Otherwise we call OS_GetEnv again to read the updated end address.
This address is where we place the stack, for the stack descends from the topmost address downwards. In theory it would crash into the top of the file workspace, however since we have a 72K allocation, 64K workspace, and a program a little over 2K, this means we have a little under 6K for the stack. That's way more than we need, so everything is fine.
; Allons-y! [would you like a jellybaby?]entry_pointENTRY; ************************************************; * *; * INITIALISE - Set up memory and validate file *; * *; ************************************************; Get our memory allocation and parameterSWI XOS_GetEnvMOV R13, R1; Stash RAM limit in R13; Do we have enough memory? We need at least 72K.; <64K workspace> SUB R1, R1, #(1<<15) ; Subtract page zero, it's a limit from zero, not a size.MOV R4, #(1<<16) ; 64KADD R4, R4, #8192; +8K = 72KCMP R1, R4; Compare corrected size with how much we wantBHS start_continue; Memory amount is higher or same, so we're good to go.; If we're here, it's because we have less than 72K available. Ask for more...MOV R0, R4; The 72K we wantMOV R1, #-1; Not interested in the Next slotSWI XWimp_SlotSizeBVS not_enough_memory; Didn't work, abort.CMP R0, R4; Did we get 72K? [RISC OS 2 corrupts R4, but nobody is using that, right?]BLO not_enough_memory; If not, abort.SWI XOS_GetEnv; Get updated end of memory and refresh command line pointerMOV R13, R1; Fall through to...
Now we must validate the file. As we expect to be called like: FirmwareID some.path.to.a.file
we simply scan through the command line looking for a space. If we find a space, what follows is assumed to be a filename.
We print a short message that quotes this filename back to the user (useful in case it fails due to typo or trailing space, etc).
Then we read the catalogue info for the object to verify that it exists and is a file. Anything under 512K is faulted immediately - that value was chosen because RISC OS 3 images saved as four ROMs are saved as 512K chunks.
We remember the file size, we may need it later.
Because we have made it to this point, we stash our return address on the stack. This means we should return by retrieving the value from the stack, not making assumptions about R14. This is especially so as from now we can call functions.
start_continue; Remember our return addressSTR R14, [R13, #-4]!
; Look for a ' ' in command lineMOV FlName, R0; R12 = Pointer to stringstart_where_spaceLDRB R5, [R12], #1; R5 = byte at StringPtr, auto-increment StringPtr afterCMP R5, #32BEQ start_found_space; Continues after the messagesCMP R5, #0BNE start_where_space; Fall-through if we get to a terminull without finding a space.start_file_failADRL R0, error_no_fileSWI OS_Write0LDR PC, [R13], #4; ==> EXITstart_found_space; Print an init messageADRL R0, msg_init_prefixSWI OS_Write0MOV R0, FlNameSWI OS_Write0ADRL R0, msg_init_suffixSWI OS_Write0; Now verify that this is a valid filenameMOV R0, #17; Read catalogue information for file, no pathMOV R1, FlNameSWI OS_File; R0 = object type (0-not, 1-file, 2-dir, 3-file/dir); R2 = load; R3 = exec; R4 = length, we'll want this later; R5 = attributesCMP R0, #1; Was it a file? Bork if not.BNE not_a_file; (code is above, after error messages)MOV FlSize, R4; Preserve file sizeCMP FlSize, #(1<<19) ; Anything under 512K is definitely bogus (under 2M is suspect!)BLO file_too_small; (code is above after messages); If we're here, then the command line parameter appears to be a file of at least 512K size.
Now it starts to get interesting. We load the first 64K of the ROM image file into our workspace. On RISC OS 5 builds, this is where the HAL lives. Then we look at the value of the very first word. This tells us a lot.
&EAE0xxxx - this is a Branch to address &FFxxxxxx which means the ROM is for the original 26 bit Archimedes range (with an ARM2, ARM250, or ARM3 processor). We fault this, not worth supporting thirty year old hardware (Arthur, RISC OS 2, RISC OS 3.1).
&EA00xxxx - this is a Branch to address &xxxxxxxx which means it's either an Iyonix or a modern ARM System-on-Chip (SoC) image.
&E59Fxxxx - this is an LDR PC from an address (that isn't important). This is how the IOMD (RiscPC/A7000) builds begin.
&0000xxxx - this is an ANDEQ instruction, with R0 as each register. This appears to be how the Titanium build begins, but the Titanium is unusual in that it isn't a ROM that appears to be executed directly (either by softload or image load at boot), but rather it is something that needs to be burnt into FlashROM, so maybe this is some sort of header?
To make our matching easier, we shift the value sixteen bits to the right, then sixteen bits to the left. This has the effect of discarding the least significant two bytes (represented as "xxxx" above).
If it is a branch, we look to see if it's an Iyonix or not. The Iyonix has a recovery loader located at the start of the ROM image, so if we see that, we know it's an Iyonix ROM. If we don't, we have to keep digging.
If it is a branch of the ARM2/ARM3 type, we bomb out with a message. I suppose we could jump straight to looking for the RISC OS module to identify the version, but we'd also need to look for the Arthur module too, so rather than complicate things, we'll just throw in the towel if we spot this.
If it's not an LDR PC instruction, it is probably a Titanium. We look for "SPRO" as the sixth word, from the embedded message "(C)2014 SPROW". Otherwise, we assume it's the IOMD build, and if this is the case, we need to check for the RISC OS module in the first chunk as the 26 bit builds of RISC OS (3.5 through to the ROLtd Select/Adjust versions) don't have a HAL so the module will appear in the first 64K.
; ********************************************; * *; * POKE AROUND WITHIN THE HAL (first chunk) *; * *; ********************************************; Okay, so now we have a pointer to a valid file (name in FlName (R12), size in FlSize (R11)); so let's load the first 64K and see what we can see...MOV R0, #0; First 64K chunkBL load_chunk; The first 64K is the HAL and some other workspacey stuff. It is here that we; will be identifying the image device information by basic pattern matching.; Set up pointersADRL WrkPtr, workspaceADD WrkEnd, WrkPtr, #(1<<16)
MOV R0, #UNKNOWN; Device is unknown until we know otherwise (then it's a known known,ADRL R1, devicetype; not an unknown known or a known unknown or... wait, I'm confused...)STRB R0, [R1]
; Look at the first wordLDR R0, [WrkPtr]
MOV R1, R0, LSR#16; These two, same asMOV R1, R1, LSL#16; AND R1, R0, #&FFFF0000; It will be:; &EAE0xxxx -> B &FFxxxxxx -> 26 bit Archimedes era; &EA00xxxx -> B &xxxxxxxx -> Modern SoC / Iyonix softload; &E59Fxxxx -> LDR PC, &xxxxxxxx -> IOMD; &00000000 -> ANDEQ R0, R0, R0, LSL #16 -> Titanium; Is it a modern SoC image or an Iyonix softload?LDR R2, firstword_branchCMP R1, R2BEQ is_it_iyonix; IS a branch, but Iyonix does that too, so check this; Is it an Archimdes (ARM2/ARM3) image? You know somebody's gonna try...LDR R2, firstword_archieCMP R1, R2BEQ oh_ffs; Is it an IOMD softload image?LDR R2, firstword_ldrpcCMP R1, R2BNE is_it_titanium; NOT an LDR PC, so is it a Titanium?; If here, it's the IOMD buildADRL R0, devicetypeMOV R1, #IOMDSTRB R1, [R0]
B check_for_riscos_here; Image ID'd (IOMD), so see if RISC OS is here.is_it_titanium; Is it a Titanium FlashROM image?LDR R2, firstword_andeqCMP R1, R2BNE keep_digging_for_device_identity; Not a Titanium, so let's try harder.; A file of NULLs would match the above test, so look for Sprow ID; I like how he starts the ID string "(C)2014", or: bracket, C, bracket, year (no space).; It's very BBC MOS, isn't it?LDR R1, [WrkPtr, #&14]
LDR R2, sixthword_sprowCMP R1, R2BNE keep_digging_for_device_identity; Not a Titanium, so let's try harder.; If here, it's the Titanium FlashROM buildADRL R0, devicetypeMOV R1, #TITANICSTRB R1, [R0]
B examine_second_chunk; Image ID'd (Titanium), so go look at the second chunkis_it_iyonix; An Iyonix has a recovery loader near the start of the first chunk, so let's whizz; through looking for that.ADRL R0, iyonix_wordsLDMIA R0, {R3, R4} ; R3 is first word to check, R4 is secondMOV R0, R3; Set up to look for the first wordBL scan_prepare; Start at the beginningiyonix_keep_goingBL scan_workspace; Look for itBEQ keep_digging_for_device_identity; First word found, so check the second wordLDR R0, [WrkPtr]
CMP R0, R4BNE iyonix_keep_going; Keep on looking; Fall though if tests are goodADRL R0, devicetypeMOV R1, #IYONIXSTRB R1, [R0]
B examine_second_chunk; ID'd, so go look at the second chunk
As said above, the 26 bit versions of RISC OS for IOMD hardware will not have a HAL, so the hidden "RISC OS" module will appear in the first chunk. So we need to check to see if this is the case, and if it is, jump to looking for the module version and date.
check_for_riscos_here; IOMD build versions of Acorn-era RISC OS have no HAL, so the hidden RISC OS; module is present earlier, in the first chunk. So if we can find the RISC OS; module in this, first, chunk, skip directly to the information reading part; without loading the second chunk. It doesn't matter if we ignore the vector; high/low tests, IOMD doesn't do this anyway.ADRL R0, kernelwords; Load kernel ID wordsLDMIA R0, {R3-R6}
BL scan_prepareearly_module_scan_loopMOV R0, R5; -> "RISC"BL scan_workspaceBEQ examine_second_chunk; Can't find kernel in IOMD build? Probably a HAL version...; "RISC" found, so check second word to see if it's the module.LDR R1, [WrkPtr]
CMP R1, R6; -> " OS"BNE early_module_scan_loop; If not, keep going.B module_early_entry; Otherwise, jump to deal with it.
If the device has not been identified yet (other than an ARM SoC), we will need to dig a little deeper by performing some pattern matching by scanning the HAL.
We look for "OMAP" (&50414D4F). If this is found, we then look to see if the next word is either "3 vi" (&69762033) or "4 vi" (&69762034) to determine if this is an OMAP3 (Beagleboard, etc) or OMAP4 (Pandaboard, etc).
If we don't find "OMAP", we scan all over again looking for "BCM2" (&324D4342) followed by "835 " (&20353338) which will identify the board as one of the RaspberryPi family. As the same ROM image works on all Pi models, it doesn't matter which it actually is.
FirmwareID cannot identify iMX6 ROM images. This is because there are no such images available from the RISC OS Open website.
keep_digging_for_device_identity; We come here after preliminary examination of the device. Device type will be; identified as IOMD, Titanium, or unknown. If unknown, we need to dig deeper.; Look to see if the device has already been identified (IOMD or Titanium).; If it has, skip the identity checks.ADRL R0, devicetypeLDRB R1, [R0]
CMP R1, #0BNE examine_second_chunk; If we have a device ID, look for the remaining fun stuff.; Okay, so let's see what this image is for.ADRL R0, devicewords; Load device ID wordsLDMIA R0, {R3-R7}
; Is it an OMAP?BL scan_prepareomap_scan_loopMOV R0, R3; -> "OMAP"BL scan_workspaceBEQ try_pi; No "OMAP" found, so see if it's a Pi; Check second word to see if we can ID which OMAP this isLDR R1, [WrkPtr]
CMP R1, R4; OMAP3?BEQ is_an_omap3CMP R1, R5; OMAP4?BEQ is_an_omap4; Else, keep chugging alongB omap_scan_loopis_an_omap3ADR R0, devicetypeMOV R1, #OMAP3STRB R1, [R0]
B examine_second_chunk; Image ID'd (OMAP3), so go look at the second chunkis_an_omap4ADR R0, devicetypeMOV R1, #OMAP4STRB R1, [R0]
B examine_second_chunk; Image ID'd (OMAP4), so go look at the second chunktry_pi; Let's see if this is a PiBL scan_preparepi_scan_loopMOV R0, R6; -> "BCM2"BL scan_workspaceBEQ examine_second_chunk; No idea, give up and look at the second chunk; Verify the second wordLDR R1, [WrkPtr]
CMP R1, R7BNE pi_scan_loop; No match, keep on looking; Else...it IS a Pi; But - wait - it might be the Pico build. Is the ROM exactly 2MB?ADR R0, devicetypeCMP FlSize, #(1<<21)
MOVEQ R1, #PIPICO; Yes, it's a Pico.MOVNE R1, #PI; Else it's a regular Pi.STRB R1, [R0]
; Fall through to...
On the HAL builds, we now load the second 64K chunk from the file and we search for a specific instruction MCR CP15, 0, R8, C1, C0, which luckily for us, only appears once. If we find this instruction, we check the word prior to see if it is ORR R8, R8, #&2000. If it is, then this is a high vector build of RISC OS.
We know this, from the following part of the kernel startup code (the highlighted instructions are what we're looking for):
ARM_read_control v5, NE
[ CacheOff
ORR v5, v5, #MMUC_M ; MMU on
ORR v5, v5, #MMUC_R ; ROM mode enable
|
ORR v5, v5, #MMUC_W+MMUC_C+MMUC_M ; Write buffer, data cache, MMU on
ORR v5, v5, #MMUC_R+MMUC_Z ; ROM mode enable, branch predict enable
]
[ MEMM_Type = "VMSAv6"
ORR v5, v5, #MMUC_XP ; Extended pages enabled (v6)
BIC v5, v5, #MMUC_TRE+MMUC_AFE ; TEX remap, Access Flag disabled
BIC v5, v5, #MMUC_EE+MMUC_TE+MMUC_VE ; Exceptions = nonvectored LE ARM
[ SupportARMv6 :LAND: NoARMv7
; Deal with a couple of ARM11 errata
ARM_read_ID lr
LDR a4, =&FFF0
AND lr, lr, a4
LDR a4, =&B760
TEQ lr, a4
BNE %FT01
ORR v5, v5, #MMUC_FI ; Erratum 716151: Disable hit-under-miss (enable fast interrupt mode) to
prevent D-cache corruption from D-cache cleaning (the other workaround,
ensuring a DSB exists inbetween the clean op and the next store access
to that cache line, feels a bit heavy-handed since we'd probably have
to disable IRQs to make it fully safe)
; Update the aux control register
MRC p15, 0, lr, c1, c0, 1
; Bit 28: Erratum 714068: Set PHD bit to prevent deadlock from PLI or I-cache invalidate by MVA
; Bit 31: Erratum 716151: Set FIO bit to override some of the behaviour implied by FI bit
ORR lr, lr, #(1:SHL:28)+(1:SHL:31)
MCR p15, 0, lr, c1, c0, 1
myISB ,lr
01
]
]
[ NoUnaligned
ORR v5, v5, #MMUC_A ; Alignment exceptions on
]
[ HiProcVecs
ORR v5, v5, #MMUC_V ; High processor vectors enabled
]
MMUon_instr
; Note, no RAM access until we've reached MMUon_nol1ptoverlap and the flat
; logical-physical mapping of the ROM has been removed (we can't guarantee that
; the RAM mapping hasn't been clobbered, and SP is currently bogus).
ARM_write_control v5
However, since the HAL versions of RISC OS use the same basic startup code, this instruction also appears on the IOMD builds of RISC OS, so if this is the case, we simply skip straight to looking for the RISC OS module.
; ***************************************; * *; * READ THE VECTOR TYPE (second chunk) *; * *; ***************************************examine_second_chunk; Okay, we're now going to load the second 64K chunk from this image.MOV R0, #1BL load_chunk; The second chunk is the start of the OS image. It contains the generic bring-up code; and the hidden "RISC OS" module (that preceeds "UtilityModule", it's the kernel!).; The init code will tell us if this ROM is low or high vector; and the "RISC OS"; module will give us the OS version and build date.; This stuff is ALWAYS available, so we can read all of this information directly from; the image regardless of whether or not the image is compressed, as the init code cannot; be compressed as it's that which brings up the machine (the HAL is minimal by intent); and you can't compress the core kernel if it's that which decompresses the rest of the OS!;; That makes OUR job a heck of a lot simpler.; First up, scan the kernel looking to see which vector type we have.; Refer to: https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/HAL?rev=4.8.2.1#l855ADRL R0, kernelwords; Load kernel ID wordsLDMIA R0, {R3-R6}
BL scan_prepareMOV R0, R3; -> MCR instruction to set up ARMv4 MMUBL scan_workspaceBEQ find_riscos_module; Skip ahead if instruction was not found.; We don't need to loop this, the instruction appears only ONCE in the ROM image(s); However, it DOES appear in the IOMD build, which has no concept of high vectors (it does other stuff too); so if this image is for an IOMD device, skip ahead.ADR R0, devicetypeLDRB R0, [R0]
CMP R0, #IOMDBEQ find_riscos_module; We found the MCR instruction, so initially flag this as a LOW vector build.ADRL R0, vectortypeMOV R1, #VECLOWSTRB R1, [R0]
; Now back up to the word prior and load thatLDR R0, [WrkPtr, #-8] ; -8 because we have advanced to the next wordCMP R0, R4; Is it the ORR instruction?; Okay, so we found the MCR and the ORR. This is a high vector ROM.ADREQL R0, vectortypeMOVEQ R1, #VECHIGHSTREQB R1, [R0]
; Fall through to...
Now to look for the RISC OS module. We either code here directly from the IOMD check (in which case we'll be looking at the first chunk of a 26 bit image) or we fall through from above (in which case it'll be the second chunk of a 32 bit HAL image). We look for "RISC" (&43534952) followed by " OS<tab>" (&09534F20). When we spot that, we skip the second word, and the following tab, and throw the remainder at OS_ReadUnsigned. This will stop at a non-number, so we can read a version such as "5.23" as 5, then 23.
We advance a bit further and then string-copy the date. As explained in the comments, there is - oddly - no SWI call to interpret dates in the official RISC OS format ("dd MMM yyyy"), so instead of trying to make sense of the date, I kept it simple and just copied it verbatim.
; ***************************************; * *; * FIND RISC OS VERSION (second chunk) *; * *; ***************************************find_riscos_moduleBL scan_preparemodule_scan_loopMOV R0, R5; -> "RISC"BL scan_workspaceBEQ damaged_file; Can't find kernel? Damaged file?; "RISC" found, so check second word to see if it's the module.LDR R1, [WrkPtr]
CMP R1, R6; -> " OS"BNE module_scan_loop; If not, keep going.; Okay, we've found the module title of the "RISC OS" module.; Format, as always, is "RISC OS5.23 (dd MMM yyyy)"module_early_entryADD WrkPtr, WrkPtr, #5; Skip next word and the following (second) tab. WrkPtr is no longer word-aligned.; ================================MOV R0, #10; Base 10MOV R1, WrkPtr; AddressSWI XOS_ReadUnsigned; Convert major version (5.xx)ADRL R4, versionmajorSTRB R2, [R4] ; Save itADD R1, R1, #1; Address of terminating character (the '.'), skip over it.; R0 preservedSWI XOS_ReadUnsigned; Convert minor version now (x.23)ADRL R4, versionminorSTRB R2, [R4] ; Save itADD WrkPtr, R1, #2; Address of terminating character (the ' '), skip over it and following bracket; I'm going to wimp out of parsing the date (in the standard format "dd MMM yyyy") into an ISO-8601 style; date, as I've not found a command in the OS to convert such a string to ordinals or somesuch.; There is Territory_ConvertTimeStringToOrdinals, and while it supports the conversion of two different date; formats but - interestingly - does not cater for the date format mandated for every module and application; Info window. Oversight much?ADR R1, versiondatedate_loop; Copy a byteLDRB R0, [WrkPtr], #1STRB R0, [R1], #1; Reached the end?CMP R0, #')'
BNE date_loop; At the end, so poke a terminull in there insteadMOV R0, #0STRB R0, [R1, #-1]
Some of the images are laid out a little differently. An example here is the OMAP3 (Beagleboard) where the code that sets up the vectors is further on in the image. Therefore, if the vector type is not yet known and it is not an IOMD build, load up the third 64K chunk of the file and scan in there. This is basically the same code as the previous vector type checking.
<
; *************************************************; * *; * LAST-DITCH READ THE VECTOR TYPE (third chunk) *; * *; *************************************************; Some images (OMAP3, for example), are laid out differently. As a last ditch attempt, if; no detected vector type and NOT the IOMD version, load the third chunk and look in there for it.ADRL R0, vectortypeADRL R1, devicetypeLDRB R0, [R0]
LDRB R1, [R1]
CMP R0, #VECIRLV; Vector unknown?BNE report_spewageCMP R1, #IOMD; Vector irrelevant on IOMDBEQ report_spewage; Load third chunkMOV R0, #2BL load_chunkADR R0, kernelwords; Load kernel ID words againLDMIA R0, {R3-R6}
BL scan_prepareMOV R0, R3; -> MCR instruction to set up ARMv4 MMUBL scan_workspaceBEQ report_spewage; Skip ahead if instruction was not found.; We found the MCR instruction, so flag this as a LOW vector build.ADRL R0, vectortypeMOV R1, #VECLOWSTRB R1, [R0]
; Now back up to the word prior and load thatLDR R0, [WrkPtr, #-8] ; -8 because we have advanced to the next wordCMP R0, R4; Is it the ORR instruction?BNE report_spewage; If not, drop out - the MCR we want only appears ONCE; Okay, so we found the MCR and the ORR. This is a high vector ROM.ADRL R0, vectortypeMOV R1, #VECHIGHSTRB R1, [R0]
; Fall through to...
Finally, some output. We start with lots of tests to determine what should be printed for the device type. Afterwards, the RISC OS version, using OS_ConvertCardinal1 to turn the numbers we read earlier back into strings for printing. I could have cheated with the first one and output the character of 48+majornumber, but this would fail should we ever hit RISC OS 10. For an example of why such assumptions are bad, go look up why the version of Windows that followed 8.x was 10, not 9. ☺
After writing out the date, we look to see if the vector type is known. If it is not, we exit immediately. If it is, we specify high or low as applicable. Then we exit.
; *****************************; * *; * REPORT WHAT WE DISCOVERED *; * *; *****************************; Okay, we're done prodding around in the image. Time to tell the user what we found.report_spewage; Report the device type.ADRL R0, report_one; "This ROM image is "SWI OS_Write0ADR R1, devicetype; Check device typeLDRB R1, [R1]
CMP R1, #TITANIC; If not Titanium or Pi...ADRLTL R0, report_two; "for an "SWILT OS_Write0ADRL R0, report_type_unknown; defaultCMP R1, #IOMDADREQL R0, report_type_iomdCMP R1, #IYONIXADREQL R0, report_type_iyonixCMP R1, #OMAP3ADREQL R0, report_type_omap3CMP R1, #OMAP4ADREQL R0, report_type_omap4CMP R1, #TITANICADREQL R0, report_type_titaniumCMP R1, #PIADREQL R0, report_type_piCMP R1, #PIPICOADREQL R0, report_type_pipicoSWI OS_Write0; If Pico, append "for a Raspberry Pi" to it.CMP R1, #PIPICOADREQL R0, report_type_piSWIEQ OS_Write0; Now report the versionADRL R0, report_three; "This RISC OS version is "SWI OS_Write0ADRL R0, versionmajor; Output major version numberLDRB R0, [R0]
ADR R1, workspaceMOV R2, #8SWI OS_ConvertCardinal1SWI OS_Write0SWI OS_WriteI+ '.' ; '.'ADRL R0, versionminor; Output minor version numberLDRB R0, [R0]
ADR R1, workspaceMOV R2, #8SWI OS_ConvertCardinal1SWI OS_Write0ADRL R0, report_four; ", dated "SWI OS_Write0ADR R0, versiondateSWI OS_Write0SWI OS_WriteI+ '.'
SWI OS_NewLine; Should we report a vector type?ADRL R1, vectortype; Read vector typeLDRB R1, [R1]
CMP R1, #VECIRLV; If irrelevant...LDREQ PC, [R13], #4; ...exit now.ADRL R0, report_five; "This is a "SWI OS_Write0ADRL R0, report_six; "low " (default)CMP R1, #VECHIGHADREQL R0, report_seven; "high "SWI OS_Write0ADRL R0, report_eight; "vector build."SWI OS_Write0; Does newline.LDR PC, [R13], #4; ==> EXIT; ****************; * *; * ! FINISHED ! *; * *; ****************
As the comment below says, our functions follow. There are a function to load a 64K chunk from the image file, a function to reset the workspace pointer (to set the scan to begin at the start (otherwise it continues)), and a function to scan the workspace for a specific word.
Perhaps the only thing of note here is the word scan routine returns its status in the Z flag, so a BL to the routine can be followed by an BEQ instruction upon the search word not being found.
At the end, some simple routines to output an error message, then exit.
; ********************; * *; * FUNCTIONS FOLLOW *; * *; ********************load_chunk ROUT; Loads a 64K chunk from the file.;; Entry: R0 is chunk to load (counts from zero); Exit : Chunk loaded (quits if failed);; Uses : R6 for stashing the file offset (from chunk number); R7 for stashing the file handle while the file is openSTMFD R13!, {R0-R7, R14}
; Work out the starting offsetMOV R6, R0, LSL #16; Offset = R0 << 16; Open the fileMOV R0, #&43; Open existing file with read-only access, no path.MOV R1, FlNameSWI XOS_FindBVS %FT20; Bomb out if can't be openedMOV R7, R0; Stash file handle in R7MOV R0, #3; Read bytes from given pointerMOV R1, R7; File handleADRL R2, workspace; BufferMOV R3, #(1<<16) ; 64KMOV R4, R6; Where to start fromSWI XOS_GBPBBVS %FT10; Bomb out (closing file) if couldn't loadMOV R0, #0; Close file (we only open it when we need to)MOV R1, R7SWI XOS_FindLDMFD R13!, {R0-R7, PC} ; Return to caller10 MOV R0, #0; Close the file on errorMOV R1, R7SWI XOS_Find20 ADRL R0, error_file_failSWI OS_Write0LDR PC, [R13], #4; ==> EXITscan_prepare; Call this before scan_workspace to start at the beginning.; (not calling it means to resume)ADR WrkPtr, workspaceMOV PC, R14scan_workspace ROUT; Scan the 64K workspace (the loaded chunk) looking for a given signature.; Entry: R0 = Word to look for; Exit : WrkPtr is set to address of found word, or ZERO.; If not found, Z is set.STMFD R13!, {R0-R1, R14}
10 LDR R1, [WrkPtr], #4; Load word into R1CMP WrkPtr, WrkEnd; Reached the end?BEQ %FT20CMP R0, R1; What we're looking for?BNE %BT10; If not, keep goingMOVS R1, #1; Ensure Z is NOT setLDMFD R13!, {R0-R1, PC} ; Return to caller20 ; Got to the end with nothing foundSUBS WrkPtr, WrkPtr; Set WrkPtr to zero, and the 'Z' flagLDMFD R13!, {R0-R1, PC} ; Return to caller; Routines to output error messages; =================================not_enough_memory; This is here so we don't need to take a branch if we DO have enough memory.ADRL R0, error_no_memorySWI OS_Write0MOV PC, R14; Uses R14 as stack not set up at this pointnot_a_file; This is here so we don't need to take a branch if the object IS a file.ADRL R0, error_not_a_fileSWI OS_Write0LDR PC, [R13], #4; ==> EXITfile_too_small; This is here so we don't need to take a branch if the file IS big enough.ADRL R0, error_too_smallSWI OS_Write0LDR PC, [R13], #4; ==> EXIToh_ffs ; <-- This says it all, somebody is trying to ID an emulator image for ARM2/3 era machines.ADRL R0, error_this_stuff_is_mesolithicSWI OS_Write0LDR PC, [R13], #4; ==> EXITdamaged_file; Couldn't locate kernel. Damaged file, or smart-ass user trying to look at "NCOS" image?ADRL R0, error_damaged_fileSWI OS_Write0LDR PC, [R13], #4; ==> EXIT
And the final part of the file is the data. This is in four parts.
The first four words are where we store our results, four bytes of data for the device type, vector type, and the number that is the major and minor part of the version. That is followed by three words (twelve bytes) for holding a copy of the module date string.
Following this are values for the pattern matching. These are LDM'd into registers. The first five are LDR'd directly. The next two (Iyonix words) are LDM'd into registers, as are the device words (the next five), and also the kernel words (the final four).
Following the matching data are the strings for the status reports and the error messages. They are all null terminated by they are not word-aligned (they don't need to be).
Finally, "workspace" is defined. This is at the end of the program and it is where the 64K chunks of data are loaded. There is a short human-readable ID message stuck here. This is only of value if a person is looking in the file. Otherwise, it is overwritten by the chunks as they are loaded.
The very final line, as explained in the comments, would raise a warning of our program grew so big that we could not afford 128 bytes (32 words) of stack, plus workspace, plus AIF header. This means our program can be up to 7936 bytes. It is currently ~2208 so we have a way to go yet. ☺
; ****************; * *; * DATA FOLLOWS *; * *; ****************; Storage of found things; BYTESdevicetypeDCB 0; Detected device typevectortypeDCB 0; Vectors irrelevant (=0), low (=1), or high (=2)versionmajorDCB 0; RISC OS version major part (5.23 -> 5)versionminorDCB 0; RISC OS version minor part (5.23 -> 23); WORDSversiondateDCD 0; "2017/11/15"DCD 0; 1234567890DCD 0; "05 Mar 2017"; Values for basic matching of first (or sixth) word in filefirstword_archieDCD &EAE00000; Archimedes!firstword_branchDCD &EA000000; It's a modern SoC that boots an image directlyfirstword_ldrpcDCD &E59F0000; It's a softloaded IOMD imagefirstword_andeqDCD &00000000; It's probably a FlashROM image for a Titaniumsixthword_sprowDCD &4F525053; Confirmation of Titanium FlashROM imageiyonix_wordsDCD &61570A0D; "Wa"DCD &6E696E72; "rnin"; Stuff to match when digging deeper and scanning entire workspacedevicewordsDCD &50414D4F; "OMAP"DCD &69762033; "3 vi" -> "OMAP3 video controller"DCD &69762034; "4 vi" -> "OMAP4 video controller"DCD &324D4342; "BCM2"DCD &20353338; "835 " -> "BCM2835 VDU device"; Stuff to match when rummaging around in the kernelkernelwordsDCD &EE018F10; MCR CP15, 0, R8, C1, C0 -> Set up MMU, HighVec is word priorDCD &E3888A02; ORR R8, R8, #&2000 -> If present, this is High VectorDCD &43534952; "RISC"DCD &09534F20; " OS" -> Find low level "RISC OS" module; Message is: Examining ""...msg_init_prefix= "Examining ", 34, 0msg_init_suffix= 34, "...\r\n", 0; The report messagesreport_one= "This ROM image is ", 0report_two= "for an ", 0report_type_unknown= "unknown device.\r\n", 0report_type_iomd= "IOMD system.\r\n", 0report_type_iyonix= "Iyonix.\r\n", 0report_type_omap3= "OMAP3 board (Beagleboard, etc).\r\n", 0report_type_omap4= "OMAP4 board (Pandaboard, etc).\r\n", 0report_type_titanium= "a Titanium FlashROM image.\r\n", 0report_type_pi= "for a RaspberryPi.\r\n", 0report_type_pipico= "the Pico version ", 0report_three= "It is RISC OS ", 0report_four= ", dated ", 0report_five= "It is a ", 0report_six= "low ", 0report_seven= "high ", 0report_eight= "vector build.\r\n", 0; All the error messageserror_no_file= "Syntax: FirmwareID \r\n", 0error_no_memory= "Not enough memory (need 72K).\r\n", 0error_not_a_file= "Object is not a file.\r\n", 0error_too_small= "File is too small to be a RISC OS image.\r\n", 0error_file_fail= "Unable to access file.\r\n", 0error_this_stuff_is_mesolithic= "Archimedes era ROM images are not supported!\r\n", 0error_damaged_file= "The ROM image is damaged.\r\n", 0ALIGN; *********************************************************************; * *; * BEYOND THIS POINT IS WORKSPACE (where the file chunks are loaded) *; * *; *********************************************************************workspace; File contents are loaded here.; Expects to have 64K of workspace to use.;; Stack follows, at the very end of memory.;; So if we subtract 64K for workspace, and allow 128 bytes of stack, plus 128 bytes; for the AIF header. This means our program can be up to 7936 bytes in size. Verify.; PRINT ( (72*1024) - (64*1024) - 128 - 128; 7936; Tail end message - human readable, gets overwritten.= 10, 10, "FirmwareID by Rick Murray, 2017/11/19", 10; exactly 40 bytesASSERT ( (workspace - entry_point) < 7936 )
END
And, as always we must end with "END" and a newline. Because that's how objasm likes it!
Ideas for the future:
Detection of iMX6 images (would require an image (at least the first 256K) to test)
Verify detection of ROLtd images (ditto, would require an image to test (first 256K...))
Possibly support Arthur-RISC OS 3.1 if we can be bothered.
Write our results out to system variables so they can be used in an Obey script or program that calls us?
...in which case, would we be better as a transient utility (we'd need to claim our 64K workspace from the RMA)?
As always, these ideas are your potential homework. (^_^)
Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺ ADDING COMMENTS DOES NOT WORK IF READING TRANSLATED VERSIONS.
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.
Gavin Wraith, 27th November 2017, 16:17
Rick, your blog's server seems a lot more responsive than ROOL's. Do you mind if I ask a silly technical question? I have a Logitech K260/M210 wireless combo. I bought myself a nano unifying receiver in the naive hope that I might be able to clone the combo's receiver - I have two Rpi3s on my desk. It would have been nice to have a receiver inserted into each machine, to avoid the unplugging and replugging when I switch from using one to t'other. But in vain. Is this because all devices have a unique ID and wireless pairing uses the IDs of both receiver and device?
Rick, 28th November 2017, 22:16
When the forum is in a sulk, even Yahoo! is more responsive... I guess the forum software is called "Beast" for a reason. :-)
I cannot say for certain, but I would imagine that there is some sort of pairing so that one keyboard talks only to one receiver. I have the same problem with my Bluetooth keyboard. I use it with my phone and the iPad, and it needs to be paired with each device every single time (if different to the time before). It would have been nice if the keyboard could remember several devices, but then this raises the question that probably applies to your keyboard - if more than one receiver is active, which one is the input sent to?
David Boddie, 2nd December 2017, 15:44
It's funny that you picked up on my post because I thought I'd managed to kill that discussion thread. Not that I was aiming to do that - it just tends to happen. I actually assumed that people would jump on the Brexit reference and really take the discussion off-topic because, as illustrated in that thread, there are people who just can't help themselves.
The discussion also illustrated the flip side of having the Aldershot forum: it can be used as a way to kill off valid discussions that people don't want to have, even if they are relevant to the topic being discussed.
But your point about being able to discuss Brexit with intelligent people reinforces my other point that you mention: people tend to assume that others are in some way on the same wavelength or that there is common ground. You are assuming that others want to have a rational discussion about a sensitive topic, but it's not necessarily the case. You might find common ground to be able to discuss Brexit in a calm way, then find that some other political issue causes things to get heated.
It's fine to start from the viewpoint that others using the forum are intelligent, reasonable people, but even that tends to trick people into a cosy view that "because you like X, you'll like Y as well" because we're all smart people, right. That also tends to lead to the sort of laziness that excuses people from dropping random stuff into otherwise fairly focused discussions. Although it can be nice that you get to see some personality in people's messages, it can very easily lead to the cosy, chummy, random nonsense that the newsgroups were known for.
So, it was surprising that it reached the possibly correct end result that the news feed should filter out comments in the Aldershot forum. It's a technical solution to a social problem, so it will be only partly effective. Still, it should help some of the people who struggled to keep up with the news feed.
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.