cannot run latest FreeBSD on a 15 year old PC

we probably need to pad the bootcode with a known pattern until its size is a multiple of 512b. if its size is already a multiple of 512 add a whole "patterned" sector
when pmbr code reads the data should stop if the sector it just read ends with the pattern.
this way it will be backwards compatible and will minimize the bios data overwrite risk
here is a shell script which will pad a file to sector multiple and terminates it with a specific pattern
Code:
#!/bin/sh
[ -r "$1" ] || exit
s=$(stat -f  %z "$1")
r=$((($s / 512 + 1) * 512 - $s))
PAT="EOOBBOOE"
if [ $r -lt 8 ];then
    r=$(($r + 512 - 8))
else
     r=$(($r - 8))
fi
cat "$1" && head -c $r /dev/zero | tr '\0' . && echo -n $PAT
 
we probably need to pad the bootcode with a known pattern until its size is a multiple of 512b. if its size is already a multiple of 512 add a whole "patterned" sector
when pmbr code reads the data should stop if the sector it just read ends with the pattern.
this way it will be backwards compatible and will minimize the bios data overwrite risk
here is a shell script which will pad a file to sector multiple and terminates it with a specific pattern
Code:
#!/bin/sh
[ -r "$1" ] || exit
s=$(stat -f  %z "$1")
r=$((($s / 512 + 1) * 512 - $s))
PAT="EOOBBOOE"
if [ $r -lt 8 ];then
    r=$(($r + 512 - 8))
else
     r=$(($r - 8))
fi
cat "$1" && head -c $r /dev/zero | tr '\0' . && echo -n $PAT

It needs to modify pmbr and gpart bootcode -b (or the make of gptboot / gptzfsboot).
And even with that, one cannot be sure this pattern will be found in the freebsd-boot partition, so the 545k test shall remain. As the room for code is very limited, it will be difficult to impossible to have both tests.

pmbr has been modified since 14.1-RELEASE. It's supposed to stop loading at 545k and continue the booting. It just emits a warning message... Is it bugged? The Op said it was a new 15.1-RELEASE installation. I will test this case.
 
the code itself is not bugged, the 545k provision is rather large as the code now is < 200k. the risk to overwrite something important for the bios will be less if 545 was 400 or 300 or 200
 
Code:
load_boot: push %si            # Save %si
        call read
        pop %si                # Restore
        movl PART_END_LBA(%di),%eax    # See if this was the last LBA
        cmpl (%si),%eax
        jnz next_boot
        movl PART_END_LBA+4(%di),%eax
        cmpl 4(%si),%eax
        jnz next_boot
        mov %bx,%es            # Reset %es to zero
        jmp LOAD            # Jump to boot code
next_boot: addl $1,(%si)            # Next LBA
        adcl $0,4(%si)
        mov %es,%ax            # Adjust segment for next
        addw $SECSIZE/16,%ax        #  sector
        cmp $0x9000,%ax            # Don't load past 0x90000,
        jb sz_ok            #  545k should be enough for
        call err_big            #  any boot code, but warn
        mov $0x9000-SECSIZE/16,%ax    #  and truncate
sz_ok:  mov %ax,%es
        jmp load_boot

Oh... Just to read the code is enough to see the bug. It lacks a "jmp LOAD" after "mov $0x9000-SECSIZE/16,%ax".
 
You're right. I went too fast. I need to sink anew in this code and the AT&T mnemonics.
That said, I don't see another test to get out of the loop than the comparison to PART_END_LBA plus something.

A test with an oversized freebsd-boot partition will give us the answer.
 
It was pretty simple. I have a VM with 14.4-RELEASE. I first checked it boots well with BIOS (it was starting with EFI). Then, I resized the freebsd-boot partition to 1004 KB (that was the space available).

On reboot, I got "Loaded only 545k" in an infinite loop. So, the patch just doesn't work. It's amazing that no one tested the only purpose of this patch before. I mean, you change something to get a given result, you test at least what it's supposed to bring.

If I have time, I will see what I can do.
 
looks like putstr from call err_big fux and resets the SI reg which holds the address current sector read and will never reach the last lba of the partition
 
%si isn't supposed to be modified by a BIOS int, except bogus BIOS.

Re-reading the code, it goes out of the load loop only if it reaches the ending LBA of the partition. There is no other way out.

I simply modify this:
Code:
next_boot: addl $1,(%si)           # Next LBA
           adcl $0,4(%si)
           mov %es,%ax             # Adjust segment for next
           addw $SECSIZE/16,%ax    #  sector
           cmp $0x9000,%ax         # Don't load past 0x90000,
           jb sz_ok                #  545k should be enough for
           call err_big            #  any boot code, but warn
           mov %bx,%es             # Modified
           jmp LOAD                # Modified too, exit the loop
sz_ok:     mov %ax,%es
           jmp load_boot
And it works with an oversized freebsd-boot partition. It just prints the warning message.
This "truncate" instruction has no sense. If we're going to fill memory above 0x90000, just stop, there is nothing to truncate.

I will make a patch and a bug report as soon as I will have time.
 
err_big modifies si also putstr modifies bx
thats why it goes to an endless loop
why this
mov %bx,%es # Modified
bx looks to be 7 after call to putstr
 
Honestly, read the code:
Code:
load_boot: push %si            # Save %si
        call read
        pop %si                # Restore
        movl PART_END_LBA(%di),%eax    # See if this was the last LBA
        cmpl (%si),%eax
        jnz next_boot
        movl PART_END_LBA+4(%di),%eax
        cmpl 4(%si),%eax
        jnz next_boot
        mov %bx,%es            # Reset %es to zero
        jmp LOAD            # Jump to boot code
It's obvious that the only way to exit the loop is to reach the ending LBA of the partition.

But, you're right on one point, there is no use to copy %bx into %es because it has been modified by putstr. I just mimicked the exit of the loop. The code wants to reset %es to 0 before to jump.

This code works also:
Code:
next_boot: addl $1,(%si)           # Next LBA
           adcl $0,4(%si)
           mov %es,%ax             # Adjust segment for next
           addw $SECSIZE/16,%ax    #  sector
           cmp $0x9000,%ax         # Don't load past 0x90000,
           jb sz_ok                #  545k should be enough for
           call err_big            #  any boot code, but warn
           xorw %bx,%bx            # Modified
           mov %bx,%es             # Modified
           jmp LOAD                # Modified too, exit the loop
sz_ok:     mov %ax,%es
           jmp load_boot
 
what i was trying to say is the original code would still work if the call to err_big would not have altered bx and si
it would pointlessly read all the sectors over the last fitting one in the 545k but would still have worked
also it would spam with the message many times over but should have worked and loop endlessly
 
You were right. Actually, %bx and %si are modified by err_big/putstr.0. For %bx, it's obvious, but I found that to make the current code "working", I need to push and pop both %bx and %si.

That said, even with that, it doesn't work as intended as the message should only printed once.

I just focalized on the solution and not on the deep causes of the problem.

Here is the PR 298669.
 
what is confusing about the current existing code is the fact that it looks it was intended to read all the non fitting sectores (modifying ax to do that).
maybe the warning should be before the loop and just read the minimum of the part size and 1090 sectors
 
Back
Top