Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
Solra Bizna

Standardized booting of nonstandard architectures

Recommended Posts

The Lua architectures boot a built-in "machine.lua", which boots "/init.lua". OC-ARM's (non-built-in) boot0 used to boot "/boot/arm.elf", but this was changed to "/OC-ARM" for three reasons:

  • Compatible with OpenOS (which would try, and fail, to run "/boot/arm.elf" as Lua code on startup)
  • No conflict with OpenArms (or other ARM architectures)
  • Similar to standard practice for OS kernels (/mach_kernel, /vmlinuz, /kernel...)
Naturally, more advanced bootloaders will include ways of specifying alternate boot targets, but it makes sense to have a standard process for determining the default on a given architecture. I'd propose that the "standard default" be "/<arch-name>" where <arch-name> is a unique, short name for the architecture in question. (Generic names like "ARM" or "MIPS" should be avoided in favor of specific names like "OC-ARM" and "OCMIPS" and "OpenArms".) Whether this is an ELF file or whatever else would be architecture-specific.

That's all well and good for filesystem-based booting, but what about drive-based booting? For that, I propose that the first sector of a bootable drive begin with a block in a format like the following:

 

BOOT:Lua 5.2,Lua 5.3:s1+1199;OC-ARM:s6+2472;MikeKaraoke:b64+102.
The meaning of this particular block would be "Lua 5.2 and Lua 5.3 compatible code starts at sector 1, and is 1199 bytes long. OC-ARM compatible code starts at sector 6, and is 2472 bytes long. MikeKaraoke compatible code starts at byte 64 of the boot sector (which is right after this block), and is 102 bytes long." (Most drives would only be bootable for one architecture.) This syntax is potentially extensible, depending on the details of the specification. Bootable code would be required to either start on a sector boundary or be contained entirely in the first sector. Under these circumstances, the bootloader can account for the raw sector size fairly simply, even where division is prohibitively expensive. The text parsing required is also fairly simple, even on an 8-bit architecture like the 6502.

This idea is compatible with any partition table scheme of the "data at end of sector" type, like the MBR scheme.

(Here I have assumed that the first sector is numbered 0. If the sectors are 1-based, the spec will have to be changed to reflect that.)

I'd be happy to write all this up as a (pair of?) pseudo-RFC but I'm open to feedback first. I've heard that this topic has been discussed a lot on IRC.

Link to post
Share on other sites

It would probably save a few lines of code and space if you used an byte offset instead of a sector. Also it should be noted that from my tested 127 is the max number you can fit in a byte (which makes sense as it is 2^8 signed) I currently have implemented a system that uses byte offset, but it currently lacks OS compatibility information of which I will probably be using your format for.

Link to post
Share on other sites

Just went back to reading this and I forgot that I ever read it.

> The text parsing required is also fairly simple, even on an 8-bit architecture like the 6502.

...converting decimal strings to integers is pretty difficult on a 6502, actually.

I get the feeling it would be better to have a text string for architectures which handle text strings well, which then ends in a \n (10, 0x0A) and a \x00 (0, 0x00). Following that should be a binary format.

Or heck, this would be better:

 

BOOT:Lua 5.2,Lua 5.3:512+1199\n
BOOT:MikeKaraoke:64+102\n
\x00(pad up to next 16-byte boundary w/ \x00 bytes, then binary data follows:)

uint8_t magic; // 'B' for big-endian, 'b' for little-endian, 0x00 to terminate the boot list
uint8_t block_length; // measured in 16-byte units
uint16_t length; // measured in bytes
uint32_t offset; // measured in bytes where the first byte of the disk is 0
uint8_t archname[]; // NUL-terminated string

{'b', 1, 2472, 3072, "OC-ARM"},
{0x00, ...}

After all that: \x00
Alternatively, have binary boot records on sector 1, and text boot records on sector 0, which would be even better.

> Generic names like "ARM" or "MIPS" should be avoided in favor of specific names like "OC-ARM" and "OCMIPS" and "OpenArms".

Oh, I definitely did worse than that. OCMIPS uses boot.elf. By the way, that's a project that could do with someone keeping it up to date, possibly even getting the FPU to work more accurately. Perhaps mocha could work again?

Link to post
Share on other sites
On 8/24/2016 at 3:53 PM, GreaseMonkey said:

...converting decimal strings to integers is pretty difficult on a 6502, actually.

It's a pain, certainly. It doesn't require a general-purpose multiply, though. Multiplying by 10 just involves two two-bit shifts and two adds.

On 6/13/2016 at 10:43 AM, TYKUHN2 said:

It would probably save a few lines of code and space if you used an byte offset instead of a sector.

Division is much harder on some architectures than others; using sector offsets makes things much easier on those architectures. Adding a division routine could easily make the bootloader no longer fit into ROM. (Correct me if I'm wrong, but I was under the impression that the sector-based read code takes a sector number, not a byte offset. Also, the sector size may change between different configurations or different devices, so it can't be hardcoded.)

On 8/24/2016 at 3:53 PM, GreaseMonkey said:

I get the feeling it would be better to have a text string for architectures which handle text strings well, which then ends in a \n (10, 0x0A) and a \x00 (0, 0x00). Following that should be a binary format.

Or heck, this would be better:


BOOT:Lua 5.2,Lua 5.3:512+1199\n
BOOT:MikeKaraoke:64+102\n
\x00(pad up to next 16-byte boundary w/ \x00 bytes, then binary data follows:)

uint8_t magic; // 'B' for big-endian, 'b' for little-endian, 0x00 to terminate the boot list
uint8_t block_length; // measured in 16-byte units
uint16_t length; // measured in bytes
uint32_t offset; // measured in bytes where the first byte of the disk is 0
uint8_t archname[]; // NUL-terminated string

{'b', 1, 2472, 3072, "OC-ARM"},
{0x00, ...}

After all that: \x00

Alternatively, have binary boot records on sector 1, and text boot records on sector 0, which would be even better.

I definitely like the idea of separate text and binary boot records. Different architectures are likely to have radically different capabilities in terms of text processing vs. binary processing. Some bootloaders/architectures could indicate that they only respect one or the other; a JavaScript architecture might only respect text boot sectors, for example, while a 6502 architecture might only respect binary boot sectors.

I'll write up a new proposal soon.

(Also, I have now learned an important lesson about how the subscription system on this forum works. I have a temporary glut of free time, so we'll see what happens.)

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.