WIP generic bios func wrapper
This commit is contained in:
parent
a4470b4733
commit
0c14013b9d
8 changed files with 201 additions and 75 deletions
4
Makefile
4
Makefile
|
|
@ -25,7 +25,7 @@ boot.elf: $(OBJS) src/nbp.ld
|
||||||
$(LD) $(LDFLAGS) -T src/nbp.ld -o $@ $(OBJS)
|
$(LD) $(LDFLAGS) -T src/nbp.ld -o $@ $(OBJS)
|
||||||
|
|
||||||
%.o: %.S
|
%.o: %.S
|
||||||
$(CC) $(CFLAGS) -c -o $@ $(@:.o=.S)
|
$(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) $(CPPFLAGS)
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c)
|
$(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c) $(CPPFLAGS)
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
LD = ld
|
LD = ld
|
||||||
|
|
||||||
CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -m32
|
CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -ffreestanding -m32
|
||||||
|
CPPFLAGS = -I3rdparty/include
|
||||||
LDFLAGS = -m elf_i386
|
LDFLAGS = -m elf_i386
|
||||||
|
|
|
||||||
61
src/bios.S
61
src/bios.S
|
|
@ -9,27 +9,22 @@ bios_write: push %ebp
|
||||||
push %ebx
|
push %ebx
|
||||||
|
|
||||||
mov 8+0(%ebp), %edx
|
mov 8+0(%ebp), %edx
|
||||||
mov 8+4(%ebp), %ecx
|
|
||||||
|
|
||||||
PROT16
|
PROT16
|
||||||
REAL
|
REAL
|
||||||
|
|
||||||
.bwloop: test %ecx, %ecx
|
.bwloop: cmpb $0, (%edx)
|
||||||
jz .bwreturn
|
jz .bwreturn
|
||||||
|
|
||||||
xor %bx, %bx
|
xor %bx, %bx
|
||||||
mov $0x0E, %ah
|
mov $0x0E, %ah
|
||||||
mov (%edx), %al
|
mov (%edx), %al
|
||||||
|
|
||||||
push %ecx
|
|
||||||
push %edx
|
push %edx
|
||||||
int $0x10
|
int $0x10
|
||||||
pop %edx
|
pop %edx
|
||||||
pop %ecx
|
|
||||||
|
|
||||||
add $1, %edx
|
add $1, %edx
|
||||||
sub $1, %ecx
|
|
||||||
|
|
||||||
jmp .bwloop
|
jmp .bwloop
|
||||||
|
|
||||||
.bwreturn: PROT
|
.bwreturn: PROT
|
||||||
|
|
@ -77,3 +72,57 @@ _gmdone: add $24, %di
|
||||||
pop %ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.global bios_func
|
||||||
|
bios_func: push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
push %ebx
|
||||||
|
push %ebp
|
||||||
|
push %edi
|
||||||
|
push %esi
|
||||||
|
|
||||||
|
mov 8+0(%ebp), %eax
|
||||||
|
mov 8+4(%ebp), %edi
|
||||||
|
|
||||||
|
// The interrupt number is given as an immediate value to INT.
|
||||||
|
// To support any interrupt number, we use self-modifying code.
|
||||||
|
mov %al, _bf_int+1
|
||||||
|
|
||||||
|
mov 0(%edi), %eax
|
||||||
|
mov 4(%edi), %ecx
|
||||||
|
mov 8(%edi), %edx
|
||||||
|
mov 12(%edi), %ebx
|
||||||
|
mov 16(%edi), %ebp
|
||||||
|
mov 20(%edi), %esi
|
||||||
|
mov 24(%edi), %edi
|
||||||
|
|
||||||
|
PROT16
|
||||||
|
REAL
|
||||||
|
|
||||||
|
// This instruction will get written at runtime
|
||||||
|
_bf_int: .byte 0xCD, 0 // INT imm8
|
||||||
|
push $0
|
||||||
|
pushf
|
||||||
|
|
||||||
|
PROT
|
||||||
|
PROT32
|
||||||
|
|
||||||
|
push %edi
|
||||||
|
mov 8+4(%ebp), %edi
|
||||||
|
mov %eax, 0(%edi)
|
||||||
|
mov %ecx, 4(%edi)
|
||||||
|
mov %edx, 8(%edi)
|
||||||
|
mov %ebx, 12(%edi)
|
||||||
|
mov %ebp, 16(%edi)
|
||||||
|
mov %esi, 20(%edi)
|
||||||
|
pop %eax
|
||||||
|
mov %eax, 24(%edi)
|
||||||
|
|
||||||
|
pop %eax
|
||||||
|
|
||||||
|
pop %esi
|
||||||
|
pop %edi
|
||||||
|
pop %ebp
|
||||||
|
pop %ebx
|
||||||
|
mov %ebp, %esp
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
|
||||||
120
src/main.c
120
src/main.c
|
|
@ -1,8 +1,6 @@
|
||||||
//#include <stdint.h>
|
#include "std.h"
|
||||||
|
|
||||||
typedef unsigned char uint8_t;
|
#include <bootboot.h>
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
|
|
||||||
#define COM1_BASE_PORT 0x3F8
|
#define COM1_BASE_PORT 0x3F8
|
||||||
|
|
||||||
|
|
@ -20,44 +18,98 @@ outb(uint16_t port, uint8_t data)
|
||||||
__asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port));
|
__asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port));
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_write_char(char c)
|
extern void bios_write(const char *msg);
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
int line_status = inb(COM1_BASE_PORT + 5);
|
|
||||||
if (line_status & 0x20) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outb(COM1_BASE_PORT, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void serial_write(const char *msg)
|
|
||||||
{
|
|
||||||
for (const char *c = msg; *c; c++) {
|
|
||||||
outb(0xE9, *c);
|
|
||||||
//serial_write_char(*c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void bios_write(const char *msg, unsigned length);
|
|
||||||
extern void *bios_getmap(void *buffer);
|
extern void *bios_getmap(void *buffer);
|
||||||
|
|
||||||
unsigned char memmap[24 * 128];
|
extern BOOTBOOT bootboot;
|
||||||
|
|
||||||
|
#define E820_TYPE_FREE 0x1
|
||||||
|
#define E820_TYPE_RESERVED 0x2
|
||||||
|
#define E820_TYPE_RECLAIMABLE 0x3
|
||||||
|
#define E820_TYPE_NONVOLATILE 0x4
|
||||||
|
#define E820_TYPE_BADMEM 0x5
|
||||||
|
|
||||||
|
struct e820_entry {
|
||||||
|
uint64_t base;
|
||||||
|
uint64_t length;
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t xattr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct e820_entry memmap[128];
|
||||||
|
|
||||||
|
struct vesa_info {
|
||||||
|
char signature[4];
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t oem_name[2];
|
||||||
|
uint8_t capab[4];
|
||||||
|
uint16_t video_mode_offset;
|
||||||
|
uint16_t video_mode_segment;
|
||||||
|
uint16_t num_64k_blocks;
|
||||||
|
uint8_t reserved[492];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern uint16_t bios_func(uint8_t inum, uint32_t reg[]);
|
||||||
|
|
||||||
void
|
void
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
bios_write("init\r\n", 6);
|
bios_write("Netboot via fernlader v2 ...\r\n");
|
||||||
void *end = bios_getmap(memmap);
|
|
||||||
bios_write("karlos\r\n", 8);
|
memcpy(bootboot.magic, BOOTBOOT_MAGIC, sizeof bootboot.magic);
|
||||||
|
bootboot.size = 128;
|
||||||
|
bootboot.protocol = PROTOCOL_MINIMAL | LOADER_BIOS;
|
||||||
|
bootboot.numcores = 1;
|
||||||
|
|
||||||
|
bios_write("init\r\n");
|
||||||
|
struct e820_entry *end = bios_getmap(memmap);
|
||||||
|
bios_write("karlos\r\n");
|
||||||
for (int i = 0; ; i++) {
|
for (int i = 0; ; i++) {
|
||||||
unsigned char *entry = memmap + 24 * i;
|
if (&memmap[i] >= end) break;
|
||||||
if ((void *)entry >= end) break;
|
char buf[2];
|
||||||
unsigned char type = *(entry + 16);
|
buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?';
|
||||||
char c = type < 10 ? type + '0' : '?';
|
buf[1] = 0;
|
||||||
bios_write(&c, 1);
|
bios_write(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
char foo[24];
|
||||||
|
|
||||||
|
bios_write("bios_func():\r\n");
|
||||||
|
uint32_t reg[6];
|
||||||
|
reg[0] = 0xE820;
|
||||||
|
reg[1] = 24;
|
||||||
|
reg[2] = 0x534D4150;
|
||||||
|
reg[3] = 0;
|
||||||
|
reg[4] = (uint32_t)&foo;
|
||||||
|
reg[5] = 0;
|
||||||
|
uint16_t flags = bios_func(0x15, reg);
|
||||||
|
|
||||||
|
const char *hex_digits = "0123456789ABCDEF";
|
||||||
|
char buf[100];
|
||||||
|
buf[0] = hex_digits[(flags >> 12) & 0xF];
|
||||||
|
buf[1] = hex_digits[(flags >> 8) & 0xF];
|
||||||
|
buf[2] = hex_digits[(flags >> 4) & 0xF];
|
||||||
|
buf[3] = hex_digits[(flags >> 0) & 0xF];
|
||||||
|
buf[4] = ' ';
|
||||||
|
buf[5] = hex_digits[(foo[16] >> 0) & 0xF];
|
||||||
|
buf[6] = ' ';
|
||||||
|
buf[7] = 0;
|
||||||
|
|
||||||
|
bios_write(buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t reg[7];
|
||||||
|
reg[0] = (0x0E << 8) + 'J';
|
||||||
|
reg[1] = 0;
|
||||||
|
reg[2] = 0;
|
||||||
|
reg[3] = 0;
|
||||||
|
reg[4] = 0;
|
||||||
|
reg[5] = 0;
|
||||||
|
reg[6] = 0;
|
||||||
|
bios_func(0x10, reg);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
__asm__ ("hlt" :);
|
__asm__ ("hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
src/nbp.S
32
src/nbp.S
|
|
@ -30,21 +30,12 @@ a20_enable: // Of all the ways to toggle A20, we only try the Fast A20 Gate.
|
||||||
// but as our bootloader exclusively runs on 64-bit machines,
|
// but as our bootloader exclusively runs on 64-bit machines,
|
||||||
// we should not run into any of those systems.
|
// we should not run into any of those systems.
|
||||||
// Modern machines apparently don't even have the A20 line anymore.
|
// Modern machines apparently don't even have the A20 line anymore.
|
||||||
push $msg_a20
|
|
||||||
call dbgmsg
|
|
||||||
add $2, %sp
|
|
||||||
|
|
||||||
inb $0x92, %al
|
inb $0x92, %al
|
||||||
or $2, %al
|
or $2, %al
|
||||||
outb %al, $0x92
|
outb %al, $0x92
|
||||||
|
|
||||||
// prot_enter: Set up GDT, switch into 32-bit protected mode.
|
// prot_enter: Set up GDT, switch into 32-bit protected mode.
|
||||||
prot_enter:
|
prot_enter: lgdt GDT_PTR
|
||||||
push $msg_prot
|
|
||||||
call dbgmsg
|
|
||||||
add $2, %sp
|
|
||||||
|
|
||||||
lgdt GDT_PTR
|
|
||||||
|
|
||||||
PROT
|
PROT
|
||||||
PROT32
|
PROT32
|
||||||
|
|
@ -52,24 +43,6 @@ prot_enter:
|
||||||
.code32
|
.code32
|
||||||
jmp main
|
jmp main
|
||||||
|
|
||||||
.code16
|
|
||||||
dbgmsg: push %bp
|
|
||||||
mov %sp, %bp
|
|
||||||
push %ax
|
|
||||||
push %si
|
|
||||||
mov 4(%bp), %si
|
|
||||||
|
|
||||||
1: lodsb
|
|
||||||
test %al, %al
|
|
||||||
jz 2f
|
|
||||||
outb %al, $0xE9
|
|
||||||
jmp 1b
|
|
||||||
|
|
||||||
2: pop %si
|
|
||||||
pop %ax
|
|
||||||
pop %bp
|
|
||||||
ret
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
.global real_ss
|
.global real_ss
|
||||||
|
|
@ -92,6 +65,3 @@ GDT_PTR: .word GDT_SIZE - 1
|
||||||
.word GDT
|
.word GDT
|
||||||
.word 0, 0, 0
|
.word 0, 0, 0
|
||||||
|
|
||||||
msg_start: .asciz "Netboot via fernlader v2 ...\r\n"
|
|
||||||
msg_a20: .asciz " * Enabling A20 Gate\r\n"
|
|
||||||
msg_prot: .asciz " * Protected Mode\r\n"
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ SECTIONS {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
*(.bootboot)
|
bootboot = .;
|
||||||
|
. += 4K;
|
||||||
_bss_end = .;
|
_bss_end = .;
|
||||||
} :all
|
} :all
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/std.c
12
src/std.c
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "std.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
memcpy(void *dst, const void *src, size_t n)
|
||||||
|
{
|
||||||
|
void *di = dst;
|
||||||
|
__asm__ ("rep movsb"
|
||||||
|
: "+D"(di), "+S"(src), "+c"(n)
|
||||||
|
:
|
||||||
|
: "memory");
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
41
src/std.h
41
src/std.h
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef FERNLADER_STD_H
|
||||||
|
#define FERNLADER_STD_H
|
||||||
|
|
||||||
|
/* Since fernlader may be built with bog-standard GCC C compiler
|
||||||
|
* (not a freestanding cross compiler), we can't rely on any of
|
||||||
|
* the compiler-provided definitions like those in stdint.h.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// stddef.h
|
||||||
|
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
|
||||||
|
// stdint.h
|
||||||
|
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef signed short int16_t;
|
||||||
|
typedef signed int int32_t;
|
||||||
|
typedef signed long long int64_t;
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
// stdbool.h
|
||||||
|
|
||||||
|
#define true ((_Bool)1)
|
||||||
|
#define false ((_Bool)0)
|
||||||
|
|
||||||
|
typedef _Bool bool;
|
||||||
|
|
||||||
|
// string.h
|
||||||
|
|
||||||
|
void *memcpy (void *dst, const void *src, size_t n);
|
||||||
|
void *memmove(void *dst, const void *src, size_t n);
|
||||||
|
void *memset (void *dst, int c, size_t n);
|
||||||
|
int memcmp (const void *src1, const void *src2, size_t n);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue