I think you may want to look at the boot code and dig around a bit. Here's what I know.
In [FILE]sys/boot[/FILE], there's a lot of code already that makes up the loader. As the loader used to be able to boot an ia64 aka Itanium which exclusively has EFI and no BIOS, there's some EFI code available already. This may give a good starting point for 1) and 2).
In my opinion, the real challenge lies in 3). Have a look at [FILE]sys/i386/i386/locore.s[/FILE] which is the kernel's entry point. The code goes on to [FILE]init386()[/FILE] in [FILE]sys/i386/i386/machdep.c[/FILE] and then calls into [FILE]mi_startup()[/FILE] in [FILE]sys/kern/init_main.c[/FILE]. The former is the machine dependent (MD) start-up code while the latter is the machine independent (MI) code.
As the name implies, the MD code is i386 specific and I wouldn't be surprised if there were a BIOS dependency in there. In fact, it seems [FILE]init386()[/FILE] calls [FILE]getmemsize()[/FILE] from [FILE]sys/i386/i386/machdep.c[/FILE] which looks to me as if it went for the BIOS to query the system's memory size.
Also, [FILE]mi_startup()[/FILE] is the core of the SYSINIT
framework which orders and runs the constructors of various kernel subsystems. One of those subsystems is "bios32", declared in [FILE]sys/i386/i386/bios.c[/FILE]. It looks like at least the APM functionality depends on that subsystem. I don't know if anything else depends on it.
Anyways, you shouldn't be discouraged by what I'm telling you. I'm merely trying to point you to the right places of the documentation which often times is in fact the code itself.