I have been working on an assembly OS with a bootloader and console type thing, it is now getting too big for the 512 bytes allocated as the bootloader so I was wondering how I could link in an external assembly file to use without any size limit, which would be called from the bootloader. Any help would be really appreciated ;)

Do what the original PC BIOS did:
1. read the boot sector into memory
2. execute
3. read the first boot partion sector into memory
4. execute

FWIW, I had to solve this problem in 1986 for our OEM version of QNX.

Thanks, but what code would I have to use in the bootloader to open the second file? Or if it was in the second bit of memory would it open automatically? And also, I was wondering how to put more than one file into a .img file.

what code would I have to use in the bootloader to open the second file?

That depends on what kind of filesystem you are using, and what executable format the file is in. For example, my own original boot loader simply assumed that the second stage was in sector (0, 1) of a floppy disk, and was simply a binary image which could be loaded directly into memory and jumped to from the boot sector; however, that design has definite weaknesses, starting with it being dependent on the type of disk it was booting from.

A (slightly) more practical solution is that used in the classic FAT design: the size of the second-stage boot loader is given in the BIOS Parameter Block, a section of data at the beginning of the FAT boot sector, in the 'reserved sectors' field. The second stage is a binary image, just as before, but it can be of an arbitrary size defined in the BPB.

A better solution still would be that used in later versions of FAT, and in most other systems, which is to write just enough code to find the secondary file in the file system and load it. The problem there is that this can easily exceed 512 bytes, which is exactly the position you are in now.

If you haven't already done so, I would recommend reading the Bootloader Theory, Boot Sequence, and Roll Your Own Bootloader pages on the OS Dev Wiki.

Now, purely for your edification (and my ego satisfaction), I'll show you my own bootloader that I mentioned earlier (assemble with NASM):

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Verbum boot loader for FAT12
; * sets the segments for use in the boot process.
; * loads and verifies the boot image from the second sector, 
;    then transfers control  to it.
;
; Version History (note: build versions not shown) 
; pre      - June 2002 to February 2004 - early test versions
;                * sets segments, loads image from second sector          
; v 0.01 - 28 February 2004 Joseph Osako 
;               * Code base cleaned up
;               * Added BPB data for future FAT12 support
;               * renamed "Verbum Boot Loader"
; v0.02 - 8 May 2004 Joseph Osako
;               *  moved existing disk handling into separate functions
; v0.03 - 7 Sept 2006 Joseph Osako
;               * resumed work on project. Placed source files under
;                 version control (SVN)     
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;constants
;

%define boot_base   0x0000      ; the segment:offset pair for the
%define boot_offset 0x7C00  ;  boot code entrypoint

stage2_base     equ 0x1000      ; the segment:offset to load 
stage2_offset   equ 0x0000  ; the second stage into
stack_seg   equ 0x9000
stack_top   equ 0xFFFC

VBIOS           equ 0x10        ; BIOS interrupt vector for video services
ttype           equ 0x0E        ; print character, teletype mode
NULL            equ 0x00        ; end of string marker
CR          equ 0x0D        ; carriage return
LF          equ 0x0A        ; line feed 

DBIOS           equ 0x13        ; BIOS interrupt vector for disk services
disk_reset  equ 0x00        ; disk reset service
disk_read   equ 0x02        ; disk read service
tries           equ 0x03        ; number of times to attempt to access the FDD
reset_failure   equ 0x01        ; error code returned on disk reset failure
read_failure    equ 0x02        ; error code returned on disk read failure

cyl             equ 0x00        ; cylinder to read from
head            equ 0x00        ; head to read from
startsector equ 0x02        ; sector to start reading at
numsectors  equ 0x01        ; number of sectors to read


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; macros
;
%define zero(x) xor x, x

%macro write 1
   mov si, %1
   call printstr
%endmacro


[bits 16]
[org boot_offset]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; entry - the entrypoint to the code. Make a short jump passed the BPB.
entry:
  jmp short redirect
  nop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; FAT12 Boot Parameter Block - required by filesystem
OEM_ID                  db "Verb0.03"
Bytes_Per_Sector    dw 0x0200
Sectors_Per_Cluster db 0x01
Reserved_Sectors    dw 0x0001
FATs                db 0x02
Root_Entries        dw 0x00E0
Sectors_Short       dw 0x0B40
Media_Descriptor    db 0xF0        ; assumes 3.5in 1.44M disk
Sectors_Per_FAT_Short   dw 0x0009
Sectors_Per_Track   dw 0x0012
Heads               dw 0x02
Hidden_Sectors          dd 0x00000000
Sectors_Long        dd 0x00000000
Sectors_Per_FAT_Long    dd 0x00000000
Extension_Flags         dw 0x0000

; extended BPB section
Drive_Number        db 0x00
Current_Head        db 0x00
BPB_Signature       db 0x28
Serial_Number       dd 0x000001
Disk_Label              db "Verbum Boot"    ; must be exactly 11 characters
File_System     db "FAT12   "       ; must be exactly 8 characters


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; redirect - do a far jump to ensure that you have the desired 
;          segment:offset location
redirect:
  jmp boot_base:start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; start
; This is the real begining of the code. The first order of
; business is clearing the interrupts, then setting the
; segment registers and the stack pointer.  

start:
  mov ax, stack_seg
  cli
  mov ss, ax          ; set the stack at an arbitrarily high point past ES.
  mov sp,  stack_top  ; put the stack pointer to the top of SS
  sti                 ; reset ints so BIOS calls can be used
  mov ax, cs
  mov ds, ax          ; set DS == CS

  write testnumber
  mov [bootdrv], dl   ; save boot drive info for later use
  write reset

; read in the data from disk and load it to ES:BX (already initalized)
  write loading
  call read_disk
  cmp ax, reset_failure
  jne good_reset
  write reset_failed
  jmp short shutdown
good_reset:
  cmp ax, read_failure
  jne good_read
  write read_failed
  jmp short shutdown

good_read:
  write done

; set up fake return frame for code returning from second stage
  mov ax, cs
  push ax
  mov ax, re_enter
  push ax  

; fake a jump to the second stage entry point
  mov ax, stage2_base
  mov es, ax
  mov bx, stage2_offset
  push es
  push bx
  write snd_stage
  retf

re_enter:
  mov ax, cs
  mov ds, ax
  write returned

shutdown:
   write exit
halted:
   hlt
   jmp short halted

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Auxilliary functions      

;; printstr - prints the string point to by SI

printstr:
  push ax
  mov ah, ttype        ; set function to 'teletype mode'
  .print_char:   
    lodsb               ; update byte to print
    cmp al, NULL        ; test that it is not NULL
    jz short .endstr
    int  VBIOS          ; put character in AL at next cursor position
    jmp short .print_char
.endstr:
  pop ax
  ret


; reset_disk
reset_disk:
  mov dl, [bootdrv]
  zero (ah)
  mov al, disk_reset
  int DBIOS
  ret

; read_disk
read_disk:
  mov cx, tries        ; set count of attempts for disk reads
  .try_read:
    push cx
    mov cx, tries      ; set count of attempts to reset disk
    .try_reset:
      call reset_disk
      jnc short .read
      loop .try_reset       ; if the reset fails, try up to three times
      mov ax, reset_failure ; if all three fail, set an error code and return
      pop cx                ; make sure that the stack is correctly aligned
      jmp short .end_fail
  .read:
    mov ax, stage2_base
    mov es, ax
    mov dl, [bootdrv] 
    mov ch, cyl          ; cylinder
    mov dh, head         ; head
    mov cl, startsector  ; first sector 
    mov al, numsectors   ; number of sectors to load   
    mov ah, disk_read
    mov bx, stage2_offset
    int DBIOS
    jnc short .end_success
    pop cx
  loop .try_read
  mov ax, read_failure ; if attempts to read the disk fail, report error code
  jmp short .end_fail
.end_success:
  pop cx               ; make sure that the stack is correctly aligned
  zero(ax)
.end_fail:
  ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; data
testnumber  db 'Verbum bootloader v0.03.0', CR, LF, NULL
reset           db 'Resetting disk drive.', CR, LF, NULL
loading         db 'Loading stage two... ', NULL
done            db 'done.', CR, LF, NULL
snd_stage   db 'Second stage loaded, proceeding to switch context.', CR, LF, NULL
returned    db 'Control returned to first stage, ', NULL
reset_failed    db 'Could not reset drive,', NULL
read_failed db 'Could not read second stage, ', NULL
exit            db 'system halted.', NULL

bootdrv         resb 1  ; byte reserved for boot drive ID number

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; pad out to 510, and then add the last two bytes needed for a boot disk

space   times (0x0200 - 2) - ($-$$) db 0
bootsig   dw 0xAA55 

Edited 4 Years Ago by Schol-R-LEA

Okay, after a lot of thought, I have decided that it would be best if I just used GRUB. So, if anyone knows how to set up GRUB then that would be great...

This article has been dead for over six months. Start a new discussion instead.