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)
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $(@:.o=.S)
|
||||
$(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) $(CPPFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c)
|
||||
$(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c) $(CPPFLAGS)
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
CC = gcc
|
||||
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
|
||||
|
|
|
|||
61
src/bios.S
61
src/bios.S
|
|
@ -9,27 +9,22 @@ bios_write: push %ebp
|
|||
push %ebx
|
||||
|
||||
mov 8+0(%ebp), %edx
|
||||
mov 8+4(%ebp), %ecx
|
||||
|
||||
PROT16
|
||||
REAL
|
||||
|
||||
.bwloop: test %ecx, %ecx
|
||||
.bwloop: cmpb $0, (%edx)
|
||||
jz .bwreturn
|
||||
|
||||
xor %bx, %bx
|
||||
mov $0x0E, %ah
|
||||
mov (%edx), %al
|
||||
|
||||
push %ecx
|
||||
push %edx
|
||||
int $0x10
|
||||
pop %edx
|
||||
pop %ecx
|
||||
|
||||
add $1, %edx
|
||||
sub $1, %ecx
|
||||
|
||||
jmp .bwloop
|
||||
|
||||
.bwreturn: PROT
|
||||
|
|
@ -77,3 +72,57 @@ _gmdone: add $24, %di
|
|||
pop %ebp
|
||||
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;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#include <bootboot.h>
|
||||
|
||||
#define COM1_BASE_PORT 0x3F8
|
||||
|
||||
|
|
@ -20,44 +18,98 @@ outb(uint16_t port, uint8_t data)
|
|||
__asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port));
|
||||
}
|
||||
|
||||
void serial_write_char(char c)
|
||||
{
|
||||
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_write(const char *msg);
|
||||
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
|
||||
main()
|
||||
{
|
||||
bios_write("init\r\n", 6);
|
||||
void *end = bios_getmap(memmap);
|
||||
bios_write("karlos\r\n", 8);
|
||||
bios_write("Netboot via fernlader v2 ...\r\n");
|
||||
|
||||
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++) {
|
||||
unsigned char *entry = memmap + 24 * i;
|
||||
if ((void *)entry >= end) break;
|
||||
unsigned char type = *(entry + 16);
|
||||
char c = type < 10 ? type + '0' : '?';
|
||||
bios_write(&c, 1);
|
||||
if (&memmap[i] >= end) break;
|
||||
char buf[2];
|
||||
buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?';
|
||||
buf[1] = 0;
|
||||
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 (;;) {
|
||||
__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,
|
||||
// we should not run into any of those systems.
|
||||
// Modern machines apparently don't even have the A20 line anymore.
|
||||
push $msg_a20
|
||||
call dbgmsg
|
||||
add $2, %sp
|
||||
|
||||
inb $0x92, %al
|
||||
or $2, %al
|
||||
outb %al, $0x92
|
||||
|
||||
// prot_enter: Set up GDT, switch into 32-bit protected mode.
|
||||
prot_enter:
|
||||
push $msg_prot
|
||||
call dbgmsg
|
||||
add $2, %sp
|
||||
|
||||
lgdt GDT_PTR
|
||||
prot_enter: lgdt GDT_PTR
|
||||
|
||||
PROT
|
||||
PROT32
|
||||
|
|
@ -52,24 +43,6 @@ prot_enter:
|
|||
.code32
|
||||
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
|
||||
|
||||
.global real_ss
|
||||
|
|
@ -92,6 +65,3 @@ GDT_PTR: .word GDT_SIZE - 1
|
|||
.word GDT
|
||||
.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)
|
||||
*(.bss)
|
||||
. = ALIGN(4K);
|
||||
*(.bootboot)
|
||||
bootboot = .;
|
||||
. += 4K;
|
||||
_bss_end = .;
|
||||
} :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