mirror of
https://github.com/limine-bootloader/limine
synced 2025-01-20 19:42:03 +03:00
Add separate bootsector and stage2, add VGA text mode driver
This commit is contained in:
parent
276928841a
commit
3c4c1a878a
11
Makefile
11
Makefile
@ -29,12 +29,15 @@ OBJ := $(C_FILES:.c=.o)
|
||||
|
||||
all: qloader2.bin
|
||||
|
||||
qloader2.bin: $(OBJ)
|
||||
$(LD) $(LDFLAGS) $(INTERNAL_LDFLAGS) $(OBJ) -o $@
|
||||
qloader2.bin: bootsect/bootsect.bin $(OBJ)
|
||||
$(LD) $(LDFLAGS) $(INTERNAL_LDFLAGS) $(OBJ) -o stage2.bin
|
||||
cat bootsect/bootsect.bin stage2.bin > $@
|
||||
|
||||
bootsect/bootsect.bin: bootsect/bootsect.asm
|
||||
cd bootsect && nasm bootsect.asm -fbin -o bootsect.bin
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
||||
|
||||
rm -f $(OBJ) bootsect/bootsect.bin
|
||||
|
2
bochsrc
2
bochsrc
@ -6,7 +6,7 @@ megs: 512
|
||||
|
||||
clock: sync=realtime, time0=local
|
||||
|
||||
ata0-master: type=disk, path="qloader2.img", mode=flat
|
||||
ata0-master: type=disk, path="qloader2.bin", mode=flat
|
||||
|
||||
boot: c
|
||||
|
||||
|
67
bootsect/bootsect.asm
Normal file
67
bootsect/bootsect.asm
Normal file
@ -0,0 +1,67 @@
|
||||
org 0x7C00
|
||||
bits 16
|
||||
|
||||
code_start:
|
||||
|
||||
cli
|
||||
jmp 0x0000:initialise_cs
|
||||
initialise_cs:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7c00
|
||||
sti
|
||||
|
||||
mov byte [drive_number], dl
|
||||
|
||||
mov si, LoadingMsg
|
||||
call simple_print
|
||||
|
||||
; ****************** Load stage 2 ******************
|
||||
|
||||
mov si, Stage2Msg
|
||||
call simple_print
|
||||
|
||||
mov ax, 1
|
||||
mov ebx, 0x7e00
|
||||
mov cx, 7
|
||||
call read_sectors
|
||||
|
||||
jc err
|
||||
|
||||
mov si, DoneMsg
|
||||
call simple_print
|
||||
|
||||
jmp 0x7e00
|
||||
|
||||
err:
|
||||
mov si, ErrMsg
|
||||
call simple_print
|
||||
|
||||
halt:
|
||||
hlt
|
||||
jmp halt
|
||||
|
||||
;Data
|
||||
|
||||
LoadingMsg db 0x0D, 0x0A, '<qLoader 2>', 0x0D, 0x0A, 0x0A, 0x00
|
||||
Stage2Msg db 'stage1: Loading stage2...', 0x00
|
||||
ErrMsg db 0x0D, 0x0A, 'Error, system halted.', 0x00
|
||||
DoneMsg db ' DONE', 0x0D, 0x0A, 0x00
|
||||
|
||||
times 0xda-($-$$) db 0
|
||||
times 6 db 0
|
||||
|
||||
;Includes
|
||||
|
||||
%include 'simple_print.inc'
|
||||
%include 'disk.inc'
|
||||
|
||||
drive_number db 0
|
||||
|
||||
times 0x1b8-($-$$) db 0
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
122
bootsect/disk.inc
Normal file
122
bootsect/disk.inc
Normal file
@ -0,0 +1,122 @@
|
||||
read_sector:
|
||||
|
||||
; ***********************************************
|
||||
; Reads a disk sector with an LBA address
|
||||
; ***********************************************
|
||||
|
||||
; IN:
|
||||
; EAX = LBA sector to load
|
||||
; DL = Drive number
|
||||
; ES = Buffer segment
|
||||
; BX = Buffer offset
|
||||
|
||||
; OUT:
|
||||
; Carry if error
|
||||
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
push es
|
||||
pop word [.target_segment]
|
||||
mov word [.target_offset], bx
|
||||
mov dword [.lba_address_low], eax
|
||||
|
||||
xor esi, esi
|
||||
mov si, .da_struct
|
||||
mov ah, 0x42
|
||||
|
||||
clc ; Clear carry for int 0x13 because some BIOSes may not clear it on success
|
||||
|
||||
int 0x13 ; Call int 0x13
|
||||
|
||||
.done:
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
pop edx
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
ret ; Exit routine
|
||||
|
||||
align 4
|
||||
.da_struct:
|
||||
.packet_size db 16
|
||||
.unused db 0
|
||||
.count dw 1
|
||||
.target_offset dw 0
|
||||
.target_segment dw 0
|
||||
.lba_address_low dd 0
|
||||
.lba_address_high dd 0
|
||||
|
||||
|
||||
read_sectors:
|
||||
|
||||
; ********************************************
|
||||
; Reads multiple LBA addressed sectors
|
||||
; ********************************************
|
||||
|
||||
; IN:
|
||||
; EAX = LBA starting sector
|
||||
; DL = Drive number
|
||||
; ES = Buffer segment
|
||||
; EBX = Buffer offset
|
||||
; CX = Sectors count
|
||||
|
||||
; OUT:
|
||||
; Carry if error
|
||||
|
||||
push eax ; Save GPRs
|
||||
push ebx
|
||||
push ecx
|
||||
push edx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
.loop:
|
||||
|
||||
push es
|
||||
push ebx
|
||||
|
||||
mov bx, 0x7000 ; Load in a temp buffer
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
|
||||
call read_sector ; Read sector
|
||||
|
||||
pop ebx
|
||||
pop es
|
||||
|
||||
jc .done ; If carry exit with flag
|
||||
|
||||
push ds
|
||||
|
||||
mov si, 0x7000
|
||||
mov ds, si
|
||||
mov edi, ebx
|
||||
xor esi, esi
|
||||
|
||||
push ecx
|
||||
mov ecx, 512
|
||||
a32 o32 rep movsb
|
||||
pop ecx
|
||||
|
||||
pop ds
|
||||
|
||||
inc eax ; Increment sector
|
||||
add ebx, 512 ; Add 512 to the buffer
|
||||
|
||||
loop .loop ; Loop!
|
||||
|
||||
.done:
|
||||
pop edi
|
||||
pop esi
|
||||
pop edx
|
||||
pop ecx ; Restore GPRs
|
||||
pop ebx
|
||||
pop eax
|
||||
ret ; Exit routine
|
22
bootsect/simple_print.inc
Normal file
22
bootsect/simple_print.inc
Normal file
@ -0,0 +1,22 @@
|
||||
simple_print:
|
||||
|
||||
; **************************************
|
||||
; Prints a string using the BIOS
|
||||
; **************************************
|
||||
|
||||
; IN:
|
||||
; SI = points to a 0x00 terminated string
|
||||
|
||||
push ax ; Save registers
|
||||
push si
|
||||
mov ah, 0x0E ; int 0x10, function 0x0E (print character)
|
||||
.loop:
|
||||
lodsb ; Load character from string
|
||||
test al, al ; Is is the 0x00 terminator?
|
||||
jz .done ; If it is, exit routine
|
||||
int 0x10 ; Call BIOS
|
||||
jmp .loop ; Repeat!
|
||||
.done:
|
||||
pop si ; Restore registers
|
||||
pop ax
|
||||
ret ; Exit routine
|
279
drivers/vga_textmode.c
Normal file
279
drivers/vga_textmode.c
Normal file
@ -0,0 +1,279 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <lib/cio.h>
|
||||
#include <drivers/vga_textmode.h>
|
||||
|
||||
#define VIDEO_BOTTOM ((VD_ROWS * VD_COLS) - 1)
|
||||
#define VD_COLS (80 * 2)
|
||||
#define VD_ROWS 25
|
||||
|
||||
static void escape_parse(char c);
|
||||
static void text_putchar(char c);
|
||||
|
||||
static char *video_mem = (char *)0xb8000;
|
||||
static size_t cursor_offset = 0;
|
||||
static int cursor_status = 1;
|
||||
static uint8_t text_palette = 0x07;
|
||||
static uint8_t cursor_palette = 0x70;
|
||||
static int escape = 0;
|
||||
static int esc_value0 = 0;
|
||||
static int esc_value1 = 0;
|
||||
static int *esc_value = &esc_value0;
|
||||
static int esc_default0 = 1;
|
||||
static int esc_default1 = 1;
|
||||
static int *esc_default = &esc_default0;
|
||||
|
||||
static void clear_cursor(void) {
|
||||
video_mem[cursor_offset + 1] = text_palette;
|
||||
return;
|
||||
}
|
||||
|
||||
static void draw_cursor(void) {
|
||||
if (cursor_status) {
|
||||
video_mem[cursor_offset + 1] = cursor_palette;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void scroll(void) {
|
||||
// move the text up by one row
|
||||
for (size_t i = 0; i <= VIDEO_BOTTOM - VD_COLS; i++)
|
||||
video_mem[i] = video_mem[i + VD_COLS];
|
||||
// clear the last line of the screen
|
||||
for (size_t i = VIDEO_BOTTOM; i > VIDEO_BOTTOM - VD_COLS; i -= 2) {
|
||||
video_mem[i] = text_palette;
|
||||
video_mem[i - 1] = ' ';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void text_clear(void) {
|
||||
clear_cursor();
|
||||
for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
|
||||
video_mem[i] = ' ';
|
||||
video_mem[i + 1] = text_palette;
|
||||
}
|
||||
cursor_offset = 0;
|
||||
draw_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
static void text_clear_no_move(void) {
|
||||
clear_cursor();
|
||||
for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
|
||||
video_mem[i] = ' ';
|
||||
video_mem[i + 1] = text_palette;
|
||||
}
|
||||
draw_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
void init_vga_textmode(void) {
|
||||
port_out_b(0x3d4, 0x0a);
|
||||
port_out_b(0x3d5, 0x20);
|
||||
text_clear();
|
||||
return;
|
||||
}
|
||||
|
||||
static void text_enable_cursor(void) {
|
||||
cursor_status = 1;
|
||||
draw_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
static void text_disable_cursor(void) {
|
||||
cursor_status = 0;
|
||||
clear_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
static void text_set_cursor_palette(uint8_t c) {
|
||||
cursor_palette = c;
|
||||
draw_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t text_get_cursor_palette(void) {
|
||||
return cursor_palette;
|
||||
}
|
||||
|
||||
static void text_set_text_palette(uint8_t c) {
|
||||
text_palette = c;
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t text_get_text_palette(void) {
|
||||
return text_palette;
|
||||
}
|
||||
|
||||
static int text_get_cursor_pos_x(void) {
|
||||
return (cursor_offset % VD_COLS) / 2;
|
||||
}
|
||||
|
||||
static int text_get_cursor_pos_y(void) {
|
||||
return cursor_offset / VD_COLS;
|
||||
}
|
||||
|
||||
static void text_set_cursor_pos(int x, int y) {
|
||||
clear_cursor();
|
||||
cursor_offset = y * VD_COLS + x * 2;
|
||||
draw_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
void text_write(const char *buf, size_t count) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
text_putchar(buf[i]);
|
||||
}
|
||||
|
||||
static void text_putchar(char c) {
|
||||
if (escape) {
|
||||
escape_parse(c);
|
||||
return;
|
||||
}
|
||||
switch (c) {
|
||||
case 0x00:
|
||||
break;
|
||||
case 0x1B:
|
||||
escape = 1;
|
||||
return;
|
||||
case 0x0A:
|
||||
if (text_get_cursor_pos_y() == (VD_ROWS - 1)) {
|
||||
clear_cursor();
|
||||
scroll();
|
||||
text_set_cursor_pos(0, (VD_ROWS - 1));
|
||||
} else {
|
||||
text_set_cursor_pos(0, (text_get_cursor_pos_y() + 1));
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
if (cursor_offset) {
|
||||
clear_cursor();
|
||||
cursor_offset -= 2;
|
||||
video_mem[cursor_offset] = ' ';
|
||||
draw_cursor();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
clear_cursor();
|
||||
video_mem[cursor_offset] = c;
|
||||
if (cursor_offset >= (VIDEO_BOTTOM - 1)) {
|
||||
scroll();
|
||||
cursor_offset = VIDEO_BOTTOM - (VD_COLS - 1);
|
||||
} else
|
||||
cursor_offset += 2;
|
||||
draw_cursor();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
|
||||
static void sgr(void) {
|
||||
|
||||
if (esc_value0 >= 30 && esc_value0 <= 37) {
|
||||
uint8_t pal = text_get_text_palette();
|
||||
pal = (pal & 0xf0) + ansi_colours[esc_value0 - 30];
|
||||
text_set_text_palette(pal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esc_value0 >= 40 && esc_value0 <= 47) {
|
||||
uint8_t pal = text_get_text_palette();
|
||||
pal = (pal & 0x0f) + ansi_colours[esc_value0 - 40] * 0x10;
|
||||
text_set_text_palette(pal);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void escape_parse(char c) {
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
*esc_value *= 10;
|
||||
*esc_value += c - '0';
|
||||
*esc_default = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '[':
|
||||
return;
|
||||
case ';':
|
||||
esc_value = &esc_value1;
|
||||
esc_default = &esc_default1;
|
||||
return;
|
||||
case 'A':
|
||||
if (esc_default0)
|
||||
esc_value0 = 1;
|
||||
if (esc_value0 > text_get_cursor_pos_y())
|
||||
esc_value0 = text_get_cursor_pos_y();
|
||||
text_set_cursor_pos(text_get_cursor_pos_x(),
|
||||
text_get_cursor_pos_y() - esc_value0);
|
||||
break;
|
||||
case 'B':
|
||||
if (esc_default0)
|
||||
esc_value0 = 1;
|
||||
if ((text_get_cursor_pos_y() + esc_value0) > (VD_ROWS - 1))
|
||||
esc_value0 = (VD_ROWS - 1) - text_get_cursor_pos_y();
|
||||
text_set_cursor_pos(text_get_cursor_pos_x(),
|
||||
text_get_cursor_pos_y() + esc_value0);
|
||||
break;
|
||||
case 'C':
|
||||
if (esc_default0)
|
||||
esc_value0 = 1;
|
||||
if ((text_get_cursor_pos_x() + esc_value0) > (VD_COLS / 2 - 1))
|
||||
esc_value0 = (VD_COLS / 2 - 1) - text_get_cursor_pos_x();
|
||||
text_set_cursor_pos(text_get_cursor_pos_x() + esc_value0,
|
||||
text_get_cursor_pos_y());
|
||||
break;
|
||||
case 'D':
|
||||
if (esc_default0)
|
||||
esc_value0 = 1;
|
||||
if (esc_value0 > text_get_cursor_pos_x())
|
||||
esc_value0 = text_get_cursor_pos_x();
|
||||
text_set_cursor_pos(text_get_cursor_pos_x() - esc_value0,
|
||||
text_get_cursor_pos_y());
|
||||
break;
|
||||
case 'H':
|
||||
esc_value0--;
|
||||
esc_value1--;
|
||||
if (esc_default0)
|
||||
esc_value0 = 0;
|
||||
if (esc_default1)
|
||||
esc_value1 = 0;
|
||||
if (esc_value1 >= (VD_COLS / 2))
|
||||
esc_value1 = (VD_COLS / 2) - 1;
|
||||
if (esc_value0 >= VD_ROWS)
|
||||
esc_value0 = VD_ROWS - 1;
|
||||
text_set_cursor_pos(esc_value1, esc_value0);
|
||||
break;
|
||||
case 'm':
|
||||
sgr();
|
||||
break;
|
||||
case 'J':
|
||||
switch (esc_value0) {
|
||||
case 2:
|
||||
text_clear_no_move();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
escape = 0;
|
||||
text_putchar('?');
|
||||
break;
|
||||
}
|
||||
|
||||
esc_value = &esc_value0;
|
||||
esc_value0 = 0;
|
||||
esc_value1 = 0;
|
||||
esc_default = &esc_default0;
|
||||
esc_default0 = 1;
|
||||
esc_default1 = 1;
|
||||
escape = 0;
|
||||
|
||||
return;
|
||||
}
|
9
drivers/vga_textmode.h
Normal file
9
drivers/vga_textmode.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __VGA_TEXTMODE_H__
|
||||
#define __VGA_TEXTMODE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void init_vga_textmode(void);
|
||||
void text_write(const char *, size_t);
|
||||
|
||||
#endif
|
59
lib/cio.h
Normal file
59
lib/cio.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef __CIO_H__
|
||||
#define __CIO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define port_out_b(port, value) ({ \
|
||||
asm volatile ( "out dx, al" \
|
||||
: \
|
||||
: "a" (value), "d" (port) \
|
||||
: ); \
|
||||
})
|
||||
|
||||
#define port_out_w(port, value) ({ \
|
||||
asm volatile ( "out dx, ax" \
|
||||
: \
|
||||
: "a" (value), "d" (port) \
|
||||
: ); \
|
||||
})
|
||||
|
||||
#define port_out_d(port, value) ({ \
|
||||
asm volatile ( "out dx, eax" \
|
||||
: \
|
||||
: "a" (value), "d" (port) \
|
||||
: ); \
|
||||
})
|
||||
|
||||
#define port_in_b(port) ({ \
|
||||
uint8_t value; \
|
||||
asm volatile ( "in al, dx" \
|
||||
: "=a" (value) \
|
||||
: "d" (port) \
|
||||
: ); \
|
||||
value; \
|
||||
})
|
||||
|
||||
#define port_in_w(port) ({ \
|
||||
uint16_t value; \
|
||||
asm volatile ( "in ax, dx" \
|
||||
: "=a" (value) \
|
||||
: "d" (port) \
|
||||
: ); \
|
||||
value; \
|
||||
})
|
||||
|
||||
#define port_in_d(port) ({ \
|
||||
uint32_t value; \
|
||||
asm volatile ( "in eax, dx" \
|
||||
: "=a" (value) \
|
||||
: "d" (port) \
|
||||
: ); \
|
||||
value; \
|
||||
})
|
||||
|
||||
#define io_wait() ({ port_out_b(0x80, 0x00); })
|
||||
|
||||
#define disable_interrupts() ({ asm volatile ("cli"); })
|
||||
#define enable_interrupts() ({ asm volatile ("sti"); })
|
||||
|
||||
#endif
|
@ -3,19 +3,18 @@ ENTRY(main)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x7c00;
|
||||
. = 0x7e00;
|
||||
|
||||
.text : {
|
||||
bootsect_begin = .;
|
||||
KEEP(*(.early_boot*))
|
||||
KEEP(*(.entry*))
|
||||
KEEP(*(.text*))
|
||||
}
|
||||
|
||||
.data : {
|
||||
KEEP(*(.data*))
|
||||
KEEP(*(.bss*))
|
||||
. += 510 - (. - bootsect_begin);
|
||||
SHORT(0xaa55)
|
||||
. += 3584 - (. - bootsect_begin);
|
||||
}
|
||||
|
||||
}
|
||||
|
30
main.c
30
main.c
@ -1,37 +1,15 @@
|
||||
asm (
|
||||
".section .early_boot\n\t"
|
||||
"cli\n\t"
|
||||
"jmp 0x0:1f\n\t"
|
||||
"1:\n\t"
|
||||
"xor ax, ax\n\t"
|
||||
"mov ds, ax\n\t"
|
||||
"mov es, ax\n\t"
|
||||
"mov fs, ax\n\t"
|
||||
"mov gs, ax\n\t"
|
||||
"mov ss, ax\n\t"
|
||||
"mov sp, 0x7c00\n\t"
|
||||
".section .entry\n\t"
|
||||
"xor dh, dh\n\t"
|
||||
"push edx\n\t"
|
||||
"call main\n\t"
|
||||
);
|
||||
|
||||
void bios_print(const char *str) {
|
||||
asm (
|
||||
"1:\n\t"
|
||||
"lodsb\n\t"
|
||||
"test al, al\n\t"
|
||||
"jz 2f\n\t"
|
||||
"int 0x10\n\t"
|
||||
"jmp 1b\n\t"
|
||||
"2:\n\t"
|
||||
:
|
||||
: "a"(0x0e00), "S"(str)
|
||||
: "cc", "memory"
|
||||
);
|
||||
}
|
||||
#include <drivers/vga_textmode.h>
|
||||
|
||||
void main(int boot_drive) {
|
||||
// TODO
|
||||
bios_print("hello world from qloader2");
|
||||
init_vga_textmode();
|
||||
text_write("hello world", 11);
|
||||
for (;;);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user