Hi,
0b00000000 wrote:Is this any better?
Here's a list of every problem I could see. Please note that I'm a bit of a perfectionist I guess - don't let this worry you too much. The problems are:
a) NASM directives have a "user-level form" and a "primitive form". The primitive form is what the assembler uses internally, and the user level form is like a macro that can augment the primitive form. For some directives they're (currently) effectively equivalent, and for some directives things break when you use the primitive form. You should always use the user-level form unless you've got a very good reason not to. You are using the primitive form everywhere (e.g. "[bits 16]" and "[orc 0x7C00]" and you should really be using the user-level form (e.g. "bits 16" and "org 0x7C00").
b) Some (extremely old and rare now) Compaq computers expect a boot loader to begin with a "short JMP" instruction and assume the code is not bootable if it begins with something else (e.g. a "far JMP" instruction).
c) There is no reason to reset the disk system before you use disk IO; mostly because you know for a fact that the BIOS has just used it successfully to load your boot sector and therefore it must be working fine.
d) When loading sectors from disk, you should have a "retry at least 3 times" loop. If the disk is faulty you do not want to retry an infinite number of times (unless you're writing malicious code that intentionally tries to destroy floppy drives or something). Note that if/when there has been a problem, you want to reset the disk system occasionally between retries. I typically do an "if retry count is odd and not even; then reset disk system" thing. If you've retried 3 or more times and it still doesn't work, you need to inform the user using a nice descriptive error message (if possible) so they've got at least some hope of figuring out what the problem might be.
e) It is a very bad idea to assume that the BIOS left SS:SP (the stack) pointing to anywhere specific. You must initialise SS:SP yourself (just so you can know your stack is somewhere safe) before loading anything from disk; otherwise it's possible that the data you load from disk will overwrite your stack.
f) It is a bad idea to assume that the BIOS started your code. Often it did not - e.g. the BIOS started some sort of boot manager thing, which chain-loaded your code. You shouldn't assume that you're booting from "device 0x80" - whatever booted your code tells you the correct device number in DL, and you should save this value somewhere and use it for all disk IO (so that your OS can boot correctly from "device 0x81" or anything else).
g) It's also probably a bad idea to assume that whatever booted your code left the video in a sane state. You should set 80*25 mode yourself, and ask the BIOS which "video page number" is currently active. A nicer idea is to ask the BIOS if you're already in 80*25 mode and only set the video mode if you have to.
h) For boot sectors; you will have trouble cramming as much as possible into 512 bytes, and you will need to cripple your code a little to make things fit. This means that it's important to at least try to reduce code size. A simple optimisation is to load both halves of a 16-bit register at once (e.g. "mov ax,0x02 * 256 + 1" instead of "mov ah,0x02" and "mov al,1").
i) For hard disks, the first sector of the disk should contain the MBR and primary partition table (even for UEFI where it's a "protective partition table"). The first sector of the disk should not contain any OS's boot sector. An OS's boot sector belongs in the first sector of the OS's partition.
j) For hard disks, it's a bad idea to use "int 0x13, ah=0x02" because the OS's partition may be outside the small area that this function can reach. You need to use "
int 0x13, ah=0x42" instead (and fall back to "int 0x13, ah=0x02" on extremely ancient computers, if you could be bothered supporting computers that are 20+ years old, and if "int 0x13 extensions" aren't supported).
Cheers,
Brendan