OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:32 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: Linker error
PostPosted: Sat Dec 15, 2018 3:00 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Hello, here bothering again with stupid questions.
I've been trying to add an IDT to my OS (real mode). I managed to create the PIC successfully, now I try to add the IDT but when I compile I get this error from the linker:
boot.o: In function `irq0':
kernel/irq.inc:56: undefined reference to `irq0_handler'
boot.o: In function `irq1':
kernel/irq.inc:62: undefined reference to `irq1_handler'
boot.o: In function `irq2':
kernel/irq.inc:68: undefined reference to `irq2_handler'
boot.o: In function `irq3':
kernel/irq.inc:74: undefined reference to `irq3_handler'
boot.o: In function `irq4':
kernel/irq.inc:80: undefined reference to `irq4_handler'
boot.o: In function `irq5':
kernel/irq.inc:86: undefined reference to `irq5_handler'
boot.o: In function `irq6':
kernel/irq.inc:92: undefined reference to `irq6_handler'
boot.o: In function `irq7':
kernel/irq.inc:98: undefined reference to `irq7_handler'
boot.o: In function `irq8':
kernel/irq.inc:104: undefined reference to `irq8_handler'
boot.o: In function `irq9':
kernel/irq.inc:110: undefined reference to `irq9_handler'
boot.o: In function `irq10':
kernel/irq.inc:116: undefined reference to `irq10_handler'
boot.o: In function `irq11':
kernel/irq.inc:122: undefined reference to `irq11_handler'
boot.o: In function `irq12':
kernel/irq.inc:128: undefined reference to `irq12_handler'
boot.o: In function `irq13':
kernel/irq.inc:134: undefined reference to `irq13_handler'
boot.o: In function `irq14':
kernel/irq.inc:140: undefined reference to `irq14_handler'
boot.o: In function `irq15':
kernel/irq.inc:146: undefined reference to `irq15_handler'
kmain.o: In function `kernelmain':
/mnt/c/Users/nicol/Desktop/ckernel/kmain.c:26: undefined reference to `idt_init'

Here's the entire source of my OS:
https://transfer.sh/tjoLh/ckernel.tar.gz
I need to make my own interrupts, so I can my OS MS-DOS compatible.

I borrowed the PIC and IDT code from OSDev btw


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Sat Dec 15, 2018 3:34 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
konniskatt wrote:
I've been trying to add an IDT to my OS (real mode).

You can't. The IDT is a protected mode structure. In real mode, you must have an IVT instead.

As for those linker errors, are you sure you're including all of your code when you link it together? It looks like your build script might be missing some pieces.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Sat Dec 15, 2018 6:18 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Sorry for being stupid and confusing IDT with IVT.
So now, how can I make my own interruptions with IVT? OSDev wiki doesn't explain much about IVT


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Sun Dec 16, 2018 7:01 am 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
konniskatt wrote:
Sorry for being stupid and confusing IDT with IVT.
So now, how can I make my own interruptions with IVT? OSDev wiki doesn't explain much about IVT

The IVT resides at physical address 0. It has 256 4-byte entries. Each entry is a far address of the ISR (far address being a pair of 16-bit values: offset (at lower address), segment (at higher address)).

IRQs (and the int instruction) would cause FLAGS, CS, IP pushed (in that order, that is, FLAGS at higher address, CS in the middle, IP at the lower address) before the corresponding ISR is entered.

FLAGS.IF is automatically cleared upon entry thus disabling nested/recursive handling of interrupts.

Each ISR should preserve all registers and return with IRET.

IRET pops IP, CS, FLAGS from the stack to resume execution of the interrupted code.

That's about it. The rest (the PIC and I/O ports) should be agnostic of the CPU mode.

However, to program for real mode comfortably (w.r.t. segmentation and that implies interrupts too) you need a compiler that actually supports it (unless you want to write lots of asm code, which is the opposite of comfortable). AFAIK, gcc doesn't quite support it out of the box, I mean the segmentation part specifically. You want something like Open Watcom C/C++ or Smaller C instead. You'll need to learn those and how to load a DOS-style .EXE (or you could use a loader that can do that, e.g. BootProg).

It may be a good start to use OW or Smaller C in some sort of DOS, FreeDOS or DOSBox. It'll be easy to set up the IVT and try out your ISRs there. This part will be the same in DOS and your system.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Sun Dec 16, 2018 3:33 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
alexfru wrote:
IRQs (and the int instruction) would cause FLAGS, CS, IP pushed (in that order, that is, FLAGS at higher address, CS in the middle, IP at the lower address) before the corresponding ISR is entered.
I'd probably also point out that any reference to error codes in the OSDev Wiki being pushed by the processor after the return address doesn't apply in real mode.

Of course replacing interrupts in real mode has the downside in that if you don't chain to the old BIOS routines, BIOS function calls may no longer work as expected. In some cases chaining to some interrupts isn't straight forward (especially the keyboard) if you want to get it right. Example: If you intercept the hard disk controller interrupts without calling the old interrupt routines in your handler- the hard disk likely won't work. Replacing the timer interrupt (IRQ0) without calling the old one can cause a host of failures for other BIOS calls (like the floppy drive and hard drive access) that may need a timer.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 6:52 am 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Now I'm rewriting my entire OS, and now is a protected mode OS, but the linker (again) are complaining that sections overlap
section .sig loaded at [00000000000007fe,00000000000007ff] overlaps section .boot loaded at [0000000000000600,0000000000000880]
Code:
OUTPUT_FORMAT("elf32-i386");
ENTRY(boot_start);

BOOTLOADER_BASE  = 0x7c00;
BOOTLOADER_RELOC = 0x600;
SECTOR_SIZE      = 512;
KERNEL_BASE      = BOOTLOADER_RELOC + SECTOR_SIZE;

SECTIONS
{
    __boot_reloc_addr = BOOTLOADER_RELOC;
    __boot_base_addr  = BOOTLOADER_BASE;
    __sector_sizew    = SECTOR_SIZE>>1;

    . = BOOTLOADER_RELOC;

    /* Code and data in boot.o placed between 0x7c00 and 0x7e00 */
    .boot : SUBALIGN(0) {
        boot.o(.text*)
        boot.o(.rodata*)
        boot.o(.data)
    }

    . = BOOTLOADER_RELOC + 0x200 - 2;
    /* Boot signature at 510th byte from beginning of bootloader's base */
    .sig : {
        SHORT(0xaa55);
    }

    KERNEL_ADJ = KERNEL_BASE - .;
    . = KERNEL_BASE;

    __disk_load_start = .;
    __disk_load_seg   = (__disk_load_start) >> 4;

    /* Kernel code and data */
    .kernel : AT(ADDR(.kernel) - KERNEL_ADJ) SUBALIGN(4) {
        *(.text*)
        *(.rodata*)
        *(.data)
    }
    __disk_load_end = .;
    __disk_load_num_sectors = (__disk_load_end - __disk_load_start + (SECTOR_SIZE - 1)) / SECTOR_SIZE;

    .kernel.bss : SUBALIGN(4) {
        __bss_start = .;
        *(COMMON);
        *(.bss)
        . = ALIGN(4);
        __bss_end = .;
    }
    __bss_sizew = SIZEOF(.kernel.bss)>>1;

    /* Remove unnecessary sections */
    /DISCARD/ : {
        *(.eh_frame);
        *(.comment);
    }
}


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 7:09 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
This is because you have put too much code into the boot sector which is 512 bytes long and it has begun to overlap the boot signature. The reason appears to be because you have included a bunch of IRQ related routine into the boot sector (boot.asm). You should be removing that irq related INC file from the boot sector, rename it to a .asm file (place a section .text at the top) and build it as a separate assembly object (with nasm) and add that object to your linking command.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 7:33 am 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Follow their suggestions and now compile without problems, but does not jump (boot2.asm) to kernelmain (kmain.c)

boot.asm
Code:
; These symbols are defined by the linker. We use them to zero BSS section
extern __bss_start
extern __bss_sizew

; These symbols are length (in sectors) of the kernel,
; and segment in memory to start reading to
extern __disk_load_num_sectors
extern __disk_load_seg

extern __sector_sizew;

; Mmory address to relocate the bootsector from / to
extern __boot_base_addr
extern __boot_reloc_addr
extern proc_mode

; This is the C entry point defined in kmain.c
;extern kernelmain               ; kernelmain is C entry point
global boot_start               ; Make this global to suppress linker warning

KERNEL_LBA_START equ 1          ; Logical Block Address(LBA) kernel starts on
                                ;     LBA 1 = sector after boot sector
KERNEL_LBA_END   equ KERNEL_LBA_START + __disk_load_num_sectors
                                ; Logical Block Address(LBA) kernel ends at
DISK_RETRIES     equ 3          ; Number of times to retry on disk error

section .text
bits 16

; Include a BPB (1.44MB floppy with FAT12)
%include "bpb.inc"
;%include "boot2.inc"

boot_start:
    ; This code up until label .reloc must be position independent
    xor eax, eax                ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00
    mov ds, ax
    mov es, ax
    mov ss, ax                  ; Stack at 0x0000:0x0000
    mov esp, eax                ; After first push will be 0x0000:0xfffe at top of 64kb

    ; Copy bootloader from  __boot_base_addr (0x7c00) to __boot_reloc_addr (0x600)
    ; We copy the bootloader to low memory above the BIOS Data Area (BDA) to allow
    ; more space for the kernel.
    cld
    mov cx, __sector_sizew
    mov si, __boot_base_addr
    mov di, __boot_reloc_addr
    rep movsw

    ; Jump to the relocated boot sector and set CS=0
    jmp 0x0000:.reloc
.reloc:

    ; Read kernel 1 sector at a time until kernel loaded
load_kernel:
    mov [bootDevice], dl        ; Save boot drive
    mov di, __disk_load_seg     ; DI = Current segment to read into
    mov si, KERNEL_LBA_START    ; SI = LBA that kernel starts at
    jmp .chk_for_last_lba       ; Check to see if we are last sector in kernel

.read_sector_loop:
    mov bp, DISK_RETRIES        ; Set disk retry count

    call lba_to_chs             ; Convert current LBA to CHS
    mov es, di                  ; Set ES to current segment number to read into
    xor bx, bx                  ; Offset zero in segment

.retry:
    mov ax, 0x0201              ; Call function 0x02 of int 13h (read sectors)
                                ;     AL = 1 = Sectors to read
    int 0x13                    ; BIOS Disk interrupt call
    jc .disk_error              ; If CF set then disk error

.success:
    add di, 512>>4              ; Advance to next 512 byte segment (0x20*16=512)
    inc si                      ; Next LBA

.chk_for_last_lba:
    cmp si, KERNEL_LBA_END      ; Have we reached the last kernel sector?
    jl .read_sector_loop        ;     If we haven't then read next sector

.kernel_loaded:
    jmp launch_kernel           ; Do realmode initialization and run kernel

.disk_error:
    xor ah, ah                  ; Int13h/AH=0 is drive reset
    int 0x13
    dec bp                      ; Decrease retry count
    jge .retry                  ; If retry count not exceeded then try again

error_end:
    ; Unrecoverable error; print drive error; enter infinite loop
    mov si, diskErrorMsg        ; Display disk error message
    call print_string
    cli
.error_loop:
    hlt
    jmp .error_loop

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:
    mov ah, 0x0e                ; BIOS tty Print
    xor bx, bx                  ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    ret

;    Function: lba_to_chs
; Description: Translate Logical block address to CHS (Cylinder, Head, Sector).
;              Works for all valid FAT12 compatible disk geometries.
;
;   Resources: http://www.ctyme.com/intr/rb-0607.htm
;              https://en.wikipedia.org/wiki/Logical_block_addressing#CHS_conversion
;              https://stackoverflow.com/q/45434899/3857942
;              Sector    = (LBA mod SPT) + 1
;              Head      = (LBA / SPT) mod HEADS
;              Cylinder  = (LBA / SPT) / HEADS
;
;      Inputs: SI = LBA
;     Outputs: DL = Boot Drive Number
;              DH = Head
;              CH = Cylinder (lower 8 bits of 10-bit cylinder)
;              CL = Sector/Cylinder
;                   Upper 2 bits of 10-bit Cylinders in upper 2 bits of CL
;                   Sector in lower 6 bits of CL
;
;       Notes: Output registers match expectation of Int 13h/AH=2 inputs
;
lba_to_chs:
    push ax                     ; Preserve AX
    mov ax, si                  ; Copy LBA to AX
    xor dx, dx                  ; Upper 16-bit of 32-bit value set to 0 for DIV
    div word [sectorsPerTrack]  ; 32-bit by 16-bit DIV : LBA / SPT
    mov cl, dl                  ; CL = S = LBA mod SPT
    inc cl                      ; CL = S = (LBA mod SPT) + 1
    xor dx, dx                  ; Upper 16-bit of 32-bit value set to 0 for DIV
    div word [numHeads]         ; 32-bit by 16-bit DIV : (LBA / SPT) / HEADS
    mov dh, dl                  ; DH = H = (LBA / SPT) mod HEADS
    mov dl, [bootDevice]        ; boot device, not necessary to set but convenient
    mov ch, al                  ; CH = C(lower 8 bits) = (LBA / SPT) / HEADS
    shl ah, 6                   ; Store upper 2 bits of 10-bit Cylinder into
    or  cl, ah                  ;     upper 2 bits of Sector (CL)
    pop ax                      ; Restore scratch registers
    ret

get_memsz:
    int 12h
    mov si, ax
    call print_string

APM_init:
    ; Checking if APM is supported
    mov ah, 53h
    mov al, 00h
    xor bx, bx
    int 15h
    jc APM_error
    ; Disconnect to any APM interface
    mov ah, 53h
    mov al, 04h
    xor bx, bx
    int 15h
    jc .APM_discerr
    jmp .APM_noerr
    ; Connect to the real mode interface
    mov ah, 53h
    mov al, [01h]
    xor bx, bx
    int 15h
    jc APM_error
    ; Enable power management
    mov ah, 53h
    mov al, 08h
    mov bx, 0001h
    mov cx, 0001h
    int 15h
    jc APM_error

.APM_discerr:
    cmp ah, 03h
    jne APM_error

.APM_noerr:


APM_error:
    mov si, APMerrorMsg
    call print_string
    cli
    hlt

; Set up segments so they are 0, zero out the BSS memory and transfer
; control to the function kernelmain
launch_kernel:
    mov si, bootloaderMsg
    call print_string
    ;jmp APM_init
    xor ax, ax
    mov es, ax
    mov fs, ax
    mov gs, ax                  ; ES=FS=GS=0 (we set DS=SS=0 previously)

    ; We need to zero out the BSS section. We'll do it a WORD at a time
    mov edi, __bss_start        ; Start address of BSS
    mov ecx, __bss_sizew        ; Length of BSS in WORDS
                                ; Clear memory with value in AX (0x0000)
    rep stosw                   ; Do clear using string store instruction
                                ;     Clear 2 bytes at a time
    ;call dword kernelmain       ; Call kernel's "C" main entry point
   jmp proc_mode

.end_loop:                      ; Loop forever to terminate when kernel main is finished
    hlt
    jmp .end_loop


section .data
; Uncomment these lines if not using a BPB (via bpb.inc)
; numHeads:        dw 2         ; 1.44MB Floppy has 2 heads & 18 sector per track
; sectorsPerTrack: dw 18

bootDevice:      db 0x00
diskErrorMsg:    db "panic: Unrecoverable disk error!", 0x0A, 0x0D, 0
bootloaderMsg:   db "Starting...", 0x0A, 0x0D, 0
APMerrorMsg:     db "panic: APM interface not supported or failed to initialize.", 0x0A, 0x0D, 0


boot2.asm
Code:
%include "gdt.inc"
%include "a20.inc"

global proc_mode
extern kernelmain

proc_mode:
   cli
   xor ax, ax
   mov ds, ax
   mov es, ax
   mov ax, 0x9000
   mov ss, ax
   mov sp, 0xFFFF
   sti

   ;cli
   mov eax, cr0
   or eax, 1
   mov cr0, eax
   jmp check_a20 ;check_a20 returns 0 to ax if a20 is not activated
   cmp ax, 0 ; IF ax == 0 THEN
   je enable_A20 ; jump to enable_A20
   jmp InstallGDT ; Starts GDT
   
   jmp 08h:proc_mode2
   
bits 32 ; Tell to NASM that were gonna use 32 bits code (protected mode)
proc_mode2:
   mov ax, 0x10
   mov ds, ax
   mov ss, ax
   mov es, ax
   mov esp, 90000h
   call dword kernelmain
   


a20.inc
Code:
check_a20:
    pushf
    push ds
    push es
    push di
    push si

    cli

    xor ax, ax ; ax = 0
    mov es, ax

    not ax ; ax = 0xFFFF
    mov ds, ax

    mov di, 0x0500
    mov si, 0x0510

    mov al, byte [es:di]
    push ax

    mov al, byte [ds:si]
    push ax

    mov byte [es:di], 0x00
    mov byte [ds:si], 0xFF

    cmp byte [es:di], 0xFF

    pop ax
    mov byte [ds:si], al

    pop ax
    mov byte [es:di], al

    mov ax, 0
    je check_a20__exit

    mov ax, 1

check_a20__exit:
    pop si
    pop di
    pop es
    pop ds
    popf

    ret
   
enable_A20:
        cli

        call    a20wait
        mov     al,0xAD
        out     0x64,al

        call    a20wait
        mov     al,0xD0
        out     0x64,al

        call    a20wait2
        in      al,0x60
        push    eax

        call    a20wait
        mov     al,0xD1
        out     0x64,al

        call    a20wait
        pop     eax
        or      al,2
        out     0x60,al

        call    a20wait
        mov     al,0xAE
        out     0x64,al

        call    a20wait
        sti
        ret

a20wait:
        in      al,0x64
        test    al,2
        jnz     a20wait
        ret


a20wait2:
        in      al,0x64
        test    al,1
        jz      a20wait2
        ret


gdt.inc

Code:
InstallGDT:
   cli            ; clear interrupts
   pusha            ; save registers
   lgdt[toc]         ; load GDT into GDTR
   sti            ; enable interrupts
   popa            ; restore registers
   ret            ; All done!

;*******************************************
; Global Descriptor Table (GDT)
;*******************************************

gdt_data:
   dd 0             ; null descriptor
   dd 0

; gdt code:            ; code descriptor
   dw 0FFFFh          ; limit low
   dw 0             ; base low
   db 0             ; base middle
   db 10011010b          ; access
   db 11001111b          ; granularity
   db 0             ; base high

; gdt data:            ; data descriptor
   dw 0FFFFh          ; limit low (Same as code)
   dw 0             ; base low
   db 0             ; base middle
   db 10010010b          ; access
   db 11001111b          ; granularity
   db 0            ; base high


   
end_of_gdt:
toc:
   dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
   dd gdt_data          ; base of GDT


kmain.c

Code:
#include <stdint.h>
#define nl "\r\n"

// taken from osdev wiki
void putch(unsigned char c, unsigned char forecolour, unsigned char backcolour, int x, int y)
{
     uint16_t attrib = (backcolour << 4) | (forecolour & 0x0F);
     volatile uint16_t * where;
     where = (volatile uint16_t *)0xB8000 + (y * 80 + x) ;
     *where = c | (attrib << 8);
}

void println(char* str)
{
   static int x = 0;
   static int y = 0;
   while (*str)
   {
      putch(*str++, 7, 0, x, y);
      ++y;
   }
}

int kernelmain()
{
   println("Hello protected mode!"nl);
   return 0;
}


Last edited by deleted8917 on Mon Dec 17, 2018 9:13 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 8:23 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
You don't show us the contents of a20.inc and gdt.inc . Hard to say without seeing everything. At this point I highly recommend using BOCHs to step through the code with the built in debugger to see where (and why) things go wrong. There is no reason to set up the stack here:
Code:
mov ax, 0x9000
   mov ss, ax
   mov sp, 0xFFFF
. You already set the real mode stack right at the beginning of the boot.asm. You should delete these lines. Secondly SS:SP of 0x9000:0xFFFF may conflict with the EBDA (Extended BIOS Data Area) just below physical address 0xA0000 and that can cause issues, which is yet another reason to remove these. PS:setting SP to 0xFFFF can potentially degrade performance on some processors since it is an odd offset.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 9:16 am 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
MichaelPetch wrote:
You don't show us the contents of a20.inc and gdt.inc . Hard to say without seeing everything. At this point I highly recommend using BOCHs to step through the code with the built in debugger to see where (and why) things go wrong. There is no reason to set up the stack here:
Code:
mov ax, 0x9000
   mov ss, ax
   mov sp, 0xFFFF
. You already set the real mode stack right at the beginning of the boot.asm. You should delete these lines. Secondly SS:SP of 0x9000:0xFFFF may conflict with the EBDA (Extended BIOS Data Area) just below physical address 0xA0000 and that can cause issues, which is yet another reason to remove these. PS:setting SP to 0xFFFF can potentially degrade performance on some processors since it is an odd offset.

added gdt.inc, a20.inc, kmain.c
btw, the OS is rebooting constantly.


Top
 Profile  
 
 Post subject: Re: Linker error
PostPosted: Mon Dec 17, 2018 1:35 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
A lot wrong with this.
- When going into protected you need to do it with interrupts off CLI
- boot2.asm is missing a bits 16 at the top
- boot2.asm you need to set up the GDT before you turn on the protected mode bit in CR0
- boot2.asm preferable to enable a20 before entering protected mode
- In gdt.inc and a20.inc it is cleaner to put code and data in their proper sections like .data and .text (not required in this case though)
- You incorrectly transfer control to A20 and InstallGDT routines with jmp rather than call
- You branch to enable_a20 which is a JMP, not a CALL. You need to CALL enable_a20 if A20 check says A20 is off
- You unnecessarily reload the segment registers while in real mode in boot,asm
- You set up the real mode stack more than once
- You don't do anything like an infinite loop after the kernel returns from the C code
- In the kernel you do ++y when advancing to next character and it should be ++x
- Your putch routine needs to handle \r and \n characters and alter x and y accordingly. Writing those characters to the screen doesn't advance to the next line of the display automatically. I've put a quick fix in to handle \r and \n but it up to you to handle wrapping at the end of a line to the next, scrolling etc

boot.asm:
Code:
; These symbols are defined by the linker. We use them to zero BSS section
extern __bss_start
extern __bss_sizew

; These symbols are length (in sectors) of the kernel,
; and segment in memory to start reading to
extern __disk_load_num_sectors
extern __disk_load_seg

extern __sector_sizew;

; Mmory address to relocate the bootsector from / to
extern __boot_base_addr
extern __boot_reloc_addr
extern proc_mode

; This is the C entry point defined in kmain.c
;extern kernelmain               ; kernelmain is C entry point
global boot_start               ; Make this global to suppress linker warning

KERNEL_LBA_START equ 1          ; Logical Block Address(LBA) kernel starts on
                                ;     LBA 1 = sector after boot sector
KERNEL_LBA_END   equ KERNEL_LBA_START + __disk_load_num_sectors
                                ; Logical Block Address(LBA) kernel ends at
DISK_RETRIES     equ 3          ; Number of times to retry on disk error

section .text
bits 16

; Include a BPB (1.44MB floppy with FAT12)
%include "bpb.inc"

boot_start:
    ; This code up until label .reloc must be position independent
    xor eax, eax                ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00
    mov ds, ax
    mov es, ax
    mov ss, ax                  ; Stack at 0x0000:0x0000
    mov esp, eax                ; After first push will be 0x0000:0xfffe at top of 64kb

    ; Copy bootloader from  __boot_base_addr (0x7c00) to __boot_reloc_addr (0x600)
    ; We copy the bootloader to low memory above the BIOS Data Area (BDA) to allow
    ; more space for the kernel.
    cld
    mov cx, __sector_sizew
    mov si, __boot_base_addr
    mov di, __boot_reloc_addr
    rep movsw

    ; Jump to the relocated boot sector and set CS=0
    jmp 0x0000:.reloc
.reloc:

    ; Read kernel 1 sector at a time until kernel loaded
load_kernel:
    mov [bootDevice], dl        ; Save boot drive
    mov di, __disk_load_seg     ; DI = Current segment to read into
    mov si, KERNEL_LBA_START    ; SI = LBA that kernel starts at
    jmp .chk_for_last_lba       ; Check to see if we are last sector in kernel

.read_sector_loop:
    mov bp, DISK_RETRIES        ; Set disk retry count

    call lba_to_chs             ; Convert current LBA to CHS
    mov es, di                  ; Set ES to current segment number to read into
    xor bx, bx                  ; Offset zero in segment

.retry:
    mov ax, 0x0201              ; Call function 0x02 of int 13h (read sectors)
                                ;     AL = 1 = Sectors to read
    int 0x13                    ; BIOS Disk interrupt call
    jc .disk_error              ; If CF set then disk error

.success:
    add di, 512>>4              ; Advance to next 512 byte segment (0x20*16=512)
    inc si                      ; Next LBA

.chk_for_last_lba:
    cmp si, KERNEL_LBA_END      ; Have we reached the last kernel sector?
    jl .read_sector_loop        ;     If we haven't then read next sector

.kernel_loaded:
    jmp launch_kernel           ; Do realmode initialization and run kernel

.disk_error:
    xor ah, ah                  ; Int13h/AH=0 is drive reset
    int 0x13
    dec bp                      ; Decrease retry count
    jge .retry                  ; If retry count not exceeded then try again

error_end:
    ; Unrecoverable error; print drive error; enter infinite loop
    mov si, diskErrorMsg        ; Display disk error message
    call print_string
    cli
.error_loop:
    hlt
    jmp .error_loop

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:
    mov ah, 0x0e                ; BIOS tty Print
    xor bx, bx                  ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    ret

;    Function: lba_to_chs
; Description: Translate Logical block address to CHS (Cylinder, Head, Sector).
;              Works for all valid FAT12 compatible disk geometries.
;
;   Resources: http://www.ctyme.com/intr/rb-0607.htm
;              https://en.wikipedia.org/wiki/Logical_block_addressing#CHS_conversion
;              https://stackoverflow.com/q/45434899/3857942
;              Sector    = (LBA mod SPT) + 1
;              Head      = (LBA / SPT) mod HEADS
;              Cylinder  = (LBA / SPT) / HEADS
;
;      Inputs: SI = LBA
;     Outputs: DL = Boot Drive Number
;              DH = Head
;              CH = Cylinder (lower 8 bits of 10-bit cylinder)
;              CL = Sector/Cylinder
;                   Upper 2 bits of 10-bit Cylinders in upper 2 bits of CL
;                   Sector in lower 6 bits of CL
;
;       Notes: Output registers match expectation of Int 13h/AH=2 inputs
;
lba_to_chs:
    push ax                     ; Preserve AX
    mov ax, si                  ; Copy LBA to AX
    xor dx, dx                  ; Upper 16-bit of 32-bit value set to 0 for DIV
    div word [sectorsPerTrack]  ; 32-bit by 16-bit DIV : LBA / SPT
    mov cl, dl                  ; CL = S = LBA mod SPT
    inc cl                      ; CL = S = (LBA mod SPT) + 1
    xor dx, dx                  ; Upper 16-bit of 32-bit value set to 0 for DIV
    div word [numHeads]         ; 32-bit by 16-bit DIV : (LBA / SPT) / HEADS
    mov dh, dl                  ; DH = H = (LBA / SPT) mod HEADS
    mov dl, [bootDevice]        ; boot device, not necessary to set but convenient
    mov ch, al                  ; CH = C(lower 8 bits) = (LBA / SPT) / HEADS
    shl ah, 6                   ; Store upper 2 bits of 10-bit Cylinder into
    or  cl, ah                  ;     upper 2 bits of Sector (CL)
    pop ax                      ; Restore scratch registers
    ret

get_memsz:
    int 12h
    mov si, ax
    call print_string

APM_init:
    ; Checking if APM is supported
    mov ah, 53h
    mov al, 00h
    xor bx, bx
    int 15h
    jc APM_error
    ; Disconnect to any APM interface
    mov ah, 53h
    mov al, 04h
    xor bx, bx
    int 15h
    jc .APM_discerr
    jmp .APM_noerr
    ; Connect to the real mode interface
    mov ah, 53h
    mov al, [01h]
    xor bx, bx
    int 15h
    jc APM_error
    ; Enable power management
    mov ah, 53h
    mov al, 08h
    mov bx, 0001h
    mov cx, 0001h
    int 15h
    jc APM_error

.APM_discerr:
    cmp ah, 03h
    jne APM_error

.APM_noerr:


APM_error:
    mov si, APMerrorMsg
    call print_string
    cli
    hlt

; Set up segments so they are 0, zero out the BSS memory and transfer
; control to the function kernelmain
launch_kernel:
    mov si, bootloaderMsg
    call print_string
    ;jmp APM_init
    xor ax, ax
    mov es, ax                  ; ES became non-zero during the disk reads
                                ;     so we have to set it to zero again

    ; We need to zero out the BSS section. We'll do it a WORD at a time
    mov edi, __bss_start        ; Start address of BSS
    mov ecx, __bss_sizew        ; Length of BSS in WORDS
                                ; Clear memory with value in AX (0x0000)
    rep stosw                   ; Do clear using string store instruction
                                ;     Clear 2 bytes at a time
    jmp proc_mode


section .data
; Uncomment these lines if not using a BPB (via bpb.inc)
; numHeads:        dw 2         ; 1.44MB Floppy has 2 heads & 18 sector per track
; sectorsPerTrack: dw 18

bootDevice:      db 0x00
diskErrorMsg:    db "panic: Unrecoverable disk error!", 0x0A, 0x0D, 0
bootloaderMsg:   db "Starting...", 0x0A, 0x0D, 0
APMerrorMsg:     db "panic: APM interface not supported or failed to initialize.", 0x0A, 0x0D, 0
boot2.asm:
Code:
bits 16
%include "gdt.inc"
%include "a20.inc"

global proc_mode
extern kernelmain

section .text

proc_mode:

    call check_a20  ; check_a20 returns 0 to ax if a20 is not activated
    test ax, ax
    jnz load_gdt    ; If A20 already enable skip to load GDT
    call enable_A20 ; call enable_A20 to enable A20 since it appears to be off
load_gdt:
    call InstallGDT ; Starts GDT

    cli
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp 08h:proc_mode2

bits 32 ; Tell to NASM that were gonna use 32 bits code (protected mode)
proc_mode2:
    mov ax, 0x10
    mov ds, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov es, ax
    mov ss, ax
    mov esp, 90000h
    call kernelmain

.end_loop:                      ; Loop forever to terminate when kernel main is finished
    hlt
    jmp .end_loop
kmain.c:
Code:
#include <stdint.h>
#define nl "\r\n"

static int x = 0;
static int y = 0;

// taken from osdev wiki
void putch(unsigned char c, unsigned char forecolour, unsigned char backcolour)
{
    uint16_t attrib = (backcolour << 4) | (forecolour & 0x0F);
    volatile uint16_t * where;
    if (c == '\r')
       x = 0;
    else if (c == '\n')
       y++;
    else {
        where = (volatile uint16_t *)0xB8000 + (y * 80 + x) ;
        *where = c | (attrib << 8);
        x++;
    }
}

void println(char* str)
{
   while (*str)
      putch(*str++, 7, 0);
}

int kernelmain()
{
   println("Hello protected mode!"nl);
   return 0;
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: SemrushBot [Bot] and 77 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group