Compare commits
10 commits
a6dd6b4328
...
89bb0903fe
| Author | SHA1 | Date | |
|---|---|---|---|
| 89bb0903fe | |||
| 87ab2b0295 | |||
| 37f53699ff | |||
| c1737c30b7 | |||
| 0c14013b9d | |||
| a4470b4733 | |||
| c67bfdeb10 | |||
| ae735033f0 | |||
| 68d47cd451 | |||
| 441d5ef570 |
15 changed files with 544 additions and 118 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
*.o
|
*.o
|
||||||
boot.bin
|
*.swp
|
||||||
boot.elf
|
/boot.bin
|
||||||
|
/boot.elf
|
||||||
|
/serve
|
||||||
|
|
|
||||||
0
bootboot.h → 3rdparty/include/bootboot.h
vendored
0
bootboot.h → 3rdparty/include/bootboot.h
vendored
18
Makefile
18
Makefile
|
|
@ -1,11 +1,19 @@
|
||||||
-include config.mk
|
-include config.mk
|
||||||
|
|
||||||
|
OBJS=\
|
||||||
|
src/nbp.o \
|
||||||
|
src/bios.o \
|
||||||
|
src/pxe.o \
|
||||||
|
src/std.o \
|
||||||
|
src/main.o \
|
||||||
|
# end of object list
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: boot.bin
|
all: boot.bin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o boot.elf boot.bin
|
rm -f $(OBJS) boot.elf boot.bin
|
||||||
|
|
||||||
config.mk: | config.default.mk
|
config.mk: | config.default.mk
|
||||||
cp config.default.mk $@
|
cp config.default.mk $@
|
||||||
|
|
@ -14,11 +22,11 @@ boot.bin: boot.elf
|
||||||
objcopy -O binary -j .text -j .data boot.elf $@
|
objcopy -O binary -j .text -j .data boot.elf $@
|
||||||
wc -c $@
|
wc -c $@
|
||||||
|
|
||||||
boot.elf: Rnbp.o Ptftp.o Qcommon.o fernlader.ld
|
boot.elf: $(OBJS) src/nbp.ld
|
||||||
$(LD) $(LDFLAGS) -o $@ Rnbp.o Ptftp.o Qcommon.o
|
$(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)
|
||||||
|
|
|
||||||
0
Ptftp.S
0
Ptftp.S
38
Qcommon.c
38
Qcommon.c
|
|
@ -1,38 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define COM1_BASE_PORT 0x3F8
|
|
||||||
|
|
||||||
static inline uint8_t
|
|
||||||
inb(uint16_t port)
|
|
||||||
{
|
|
||||||
uint8_t data;
|
|
||||||
__asm__ ("inb %%dx, %%al" : "=a"(data) : "d"(port));
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
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
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
outb(0xE9, 'X');
|
|
||||||
serial_write_char('X');
|
|
||||||
for (;;) {
|
|
||||||
__asm__ ("hlt" :);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
CC = cc
|
#CC = /usr/local/x86_64-karlos-toolchain/bin/x86_64-karlos-gcc
|
||||||
|
#LD = /usr/local/x86_64-karlos-toolchain/bin/x86_64-karlos-ld
|
||||||
|
CC = gcc
|
||||||
LD = ld
|
LD = ld
|
||||||
|
|
||||||
CFLAGS = -no-pie -fno-pic -fno-stack-protector
|
CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -ffreestanding -m32
|
||||||
LDFLAGS = -Tfernlader.ld
|
CPPFLAGS = -I3rdparty/include
|
||||||
|
LDFLAGS = -m elf_i386
|
||||||
|
|
|
||||||
2
run-dnsmasq.sh
Executable file
2
run-dnsmasq.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
dnsmasq -u "$USER" --conf-file=dnsmasq.conf "$@"
|
||||||
125
src/bios.S
Normal file
125
src/bios.S
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
// vim: ft=gas:et:sw=12:ts=12:sts=12
|
||||||
|
|
||||||
|
.include "src/mode.S"
|
||||||
|
|
||||||
|
.global bios_write
|
||||||
|
.code32
|
||||||
|
bios_write: push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
push %ebx
|
||||||
|
|
||||||
|
mov 8+0(%ebp), %edx
|
||||||
|
|
||||||
|
PROT16
|
||||||
|
REAL
|
||||||
|
|
||||||
|
.bwloop: cmpb $0, (%edx)
|
||||||
|
jz .bwreturn
|
||||||
|
|
||||||
|
xor %bx, %bx
|
||||||
|
mov $0x0E, %ah
|
||||||
|
mov (%edx), %al
|
||||||
|
|
||||||
|
push %edx
|
||||||
|
int $0x10
|
||||||
|
pop %edx
|
||||||
|
|
||||||
|
add $1, %edx
|
||||||
|
jmp .bwloop
|
||||||
|
|
||||||
|
.bwreturn: PROT
|
||||||
|
PROT32
|
||||||
|
|
||||||
|
pop %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global bios_getmap
|
||||||
|
.code32
|
||||||
|
bios_getmap:push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
push %ebx
|
||||||
|
push %edi
|
||||||
|
|
||||||
|
mov 8+0(%ebp), %edi
|
||||||
|
|
||||||
|
PROT16
|
||||||
|
REAL
|
||||||
|
|
||||||
|
xor %ebx, %ebx
|
||||||
|
_gmnext: movl $0, 20(%di)
|
||||||
|
mov $0x534D4150, %edx // e820 magic number
|
||||||
|
mov $24, %ecx
|
||||||
|
mov $0xE820, %eax
|
||||||
|
int $0x15
|
||||||
|
jc _gmdone
|
||||||
|
test %ebx, %ebx
|
||||||
|
jz _gmdone
|
||||||
|
add $24, %di
|
||||||
|
jmp _gmnext
|
||||||
|
_gmdone: add $24, %di
|
||||||
|
|
||||||
|
|
||||||
|
PROT
|
||||||
|
PROT32
|
||||||
|
|
||||||
|
mov %edi, %eax
|
||||||
|
|
||||||
|
pop %edi
|
||||||
|
pop %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global bios_func
|
||||||
|
bios_func: push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
push %ebx
|
||||||
|
push %ebp
|
||||||
|
push %edi
|
||||||
|
push %esi
|
||||||
|
|
||||||
|
// The interrupt number is given as an immediate value to INT.
|
||||||
|
// To support any interrupt number, we use self-modifying code.
|
||||||
|
mov 8+0(%ebp), %eax
|
||||||
|
mov %al, _bf_int+1
|
||||||
|
|
||||||
|
PROT16
|
||||||
|
REAL
|
||||||
|
|
||||||
|
mov %ds:8+4(%ebp), %edi
|
||||||
|
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
|
||||||
|
|
||||||
|
// This instruction will get written at runtime
|
||||||
|
_bf_int: .byte 0xCD, 0 // INT imm8
|
||||||
|
push $0
|
||||||
|
pushf
|
||||||
|
|
||||||
|
// FIXME broken BP
|
||||||
|
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)
|
||||||
|
|
||||||
|
PROT
|
||||||
|
PROT32
|
||||||
|
|
||||||
|
pop %eax
|
||||||
|
|
||||||
|
pop %esi
|
||||||
|
pop %edi
|
||||||
|
pop %ebp
|
||||||
|
pop %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
197
src/main.c
Normal file
197
src/main.c
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
#include "std.h"
|
||||||
|
|
||||||
|
#include <bootboot.h>
|
||||||
|
|
||||||
|
#define COM1_BASE_PORT 0x3F8
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
inb(uint16_t port)
|
||||||
|
{
|
||||||
|
uint8_t data;
|
||||||
|
__asm__ ("inb %%dx, %%al" : "=a"(data) : "d"(port));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
outb(uint16_t port, uint8_t data)
|
||||||
|
{
|
||||||
|
__asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void bios_write(const char *msg);
|
||||||
|
extern void *bios_getmap(void *buffer);
|
||||||
|
|
||||||
|
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
|
||||||
|
blank_screen(uint16_t attr)
|
||||||
|
{
|
||||||
|
uint32_t reg[7];
|
||||||
|
reg[0] = (0x06 << 8);
|
||||||
|
reg[1] = 0;
|
||||||
|
reg[2] = 0xFFFF;
|
||||||
|
reg[3] = attr << 8;
|
||||||
|
reg[4] = 0;
|
||||||
|
reg[5] = 0;
|
||||||
|
reg[6] = 0;
|
||||||
|
bios_func(0x10, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
move_cursor(uint8_t row, uint8_t col)
|
||||||
|
{
|
||||||
|
uint32_t reg[7];
|
||||||
|
reg[0] = (0x02 << 8);
|
||||||
|
reg[1] = 0;
|
||||||
|
reg[2] = (row << 8) | col;
|
||||||
|
reg[3] = 0;
|
||||||
|
reg[4] = 0;
|
||||||
|
reg[5] = 0;
|
||||||
|
reg[6] = 0;
|
||||||
|
bios_func(0x10, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
display_string(uint16_t attr, const char *str)
|
||||||
|
{
|
||||||
|
uint32_t reg[7];
|
||||||
|
reg[0] = (0x13 << 8) | 0x01;
|
||||||
|
reg[1] = strlen(str);
|
||||||
|
reg[2] = 0xFFFF;
|
||||||
|
reg[3] = attr;
|
||||||
|
reg[4] = (uint32_t)str;
|
||||||
|
reg[5] = 0;
|
||||||
|
reg[6] = 0;
|
||||||
|
bios_func(0x10, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PG_PRESENT 0x001
|
||||||
|
#define PG_WRITE 0x002
|
||||||
|
#define PG_USER 0x004
|
||||||
|
#define PG_SIZE 0x080
|
||||||
|
#define PG_GLOBAL 0x100
|
||||||
|
|
||||||
|
__attribute__((aligned(4096))) uint64_t pml4[512];
|
||||||
|
__attribute__((aligned(4096))) uint64_t pdp[512];
|
||||||
|
__attribute__((aligned(4096))) uint64_t pd[512];
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
pg_setup()
|
||||||
|
{
|
||||||
|
pml4[0] = (uint64_t)(uint32_t)pdp | PG_WRITE | PG_PRESENT;
|
||||||
|
pdp[0] = (uint64_t)(uint32_t)pd | PG_WRITE | PG_PRESENT;
|
||||||
|
for (unsigned i = 0; i < 512; i++) {
|
||||||
|
pd[i] = (i * (uint64_t)0x200000) | PG_WRITE | PG_PRESENT | PG_SIZE;
|
||||||
|
}
|
||||||
|
uint64_t cr3 = (uint64_t)(uint32_t)pml4;
|
||||||
|
return cr3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PXENV {
|
||||||
|
uint8_t signature[6];
|
||||||
|
uint16_t version;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t checksum;
|
||||||
|
uint32_t rmentry;
|
||||||
|
uint32_t pmoffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exPXE {
|
||||||
|
uint8_t signature[4];
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t checksum;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint32_t undiromid;
|
||||||
|
uint32_t bcromid;
|
||||||
|
uint32_t rmentry;
|
||||||
|
uint32_t pmentry;
|
||||||
|
};
|
||||||
|
|
||||||
|
//extern uint32_t pxe_call(uint16_t func, offset, segment);
|
||||||
|
|
||||||
|
extern struct PXENV *PXENV;
|
||||||
|
extern struct exPXE *exPXE;
|
||||||
|
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
blank_screen(0x10);
|
||||||
|
move_cursor(0, 0);
|
||||||
|
//display_string(0x14, "Netboot via fernlader v2 ...\r\n");
|
||||||
|
bios_write("Going well ...\r\n");
|
||||||
|
|
||||||
|
if (memcmp(PXENV->signature, "PXENV+", 6) != 0) {
|
||||||
|
bios_write("missing PXENV+ signature\r\n");
|
||||||
|
}
|
||||||
|
if (PXENV->version >= 0x0201) {
|
||||||
|
bios_write("!PXE version\r\n");
|
||||||
|
if (memcmp(exPXE->signature, "!PXE", 4) != 0) {
|
||||||
|
bios_write("missing !PXE signature\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(bootboot.magic, BOOTBOOT_MAGIC, sizeof bootboot.magic);
|
||||||
|
bootboot.size = 128;
|
||||||
|
bootboot.protocol = PROTOCOL_MINIMAL | LOADER_BIOS;
|
||||||
|
bootboot.numcores = 1;
|
||||||
|
|
||||||
|
//display_string(0x0E, "init\r\n");
|
||||||
|
struct e820_entry *end = bios_getmap(memmap);
|
||||||
|
//display_string(0x0E, "karlos\r\n");
|
||||||
|
for (int i = 0; ; i++) {
|
||||||
|
if (&memmap[i] >= end) break;
|
||||||
|
char buf[2];
|
||||||
|
buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?';
|
||||||
|
buf[1] = 0;
|
||||||
|
bios_write(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_setup();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
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);
|
||||||
|
|
||||||
|
bios_write("what?\r\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
__asm__ ("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/mode.S
Normal file
57
src/mode.S
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
// vim: ft=gas:et:sw=12:ts=12:sts=12
|
||||||
|
|
||||||
|
.set SS_CODE16, 0x08
|
||||||
|
.set SS_DATA16, 0x10
|
||||||
|
.set SS_CODE32, 0x18
|
||||||
|
.set SS_DATA32, 0x20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.macro PROT16
|
||||||
|
.code32
|
||||||
|
mov $SS_DATA16, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %ss
|
||||||
|
ljmp $SS_CODE16, $9f
|
||||||
|
9: .code16
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro PROT32
|
||||||
|
.code16
|
||||||
|
mov $SS_DATA32, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %ss
|
||||||
|
ljmp $SS_CODE32, $9f
|
||||||
|
9: .code32
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro REAL
|
||||||
|
mov %cr0, %eax
|
||||||
|
and $0xFFFE, %ax
|
||||||
|
mov %eax, %cr0
|
||||||
|
xor %ax, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov real_ss, %ax
|
||||||
|
mov %ax, %ss
|
||||||
|
shl $4, %eax
|
||||||
|
sub %eax, %esp
|
||||||
|
ljmp $0x0000, $9f
|
||||||
|
9:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro PROT
|
||||||
|
mov %cr0, %eax
|
||||||
|
or $1, %eax
|
||||||
|
mov %eax, %cr0
|
||||||
|
xor %eax, %eax
|
||||||
|
mov $SS_DATA16, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %ss
|
||||||
|
mov real_ss, %ax
|
||||||
|
shl $4, %eax
|
||||||
|
add %eax, %esp
|
||||||
|
.endm
|
||||||
|
|
@ -1,34 +1,45 @@
|
||||||
// vim: et:sw=12:ts=12:sts=12
|
// vim: ft=gas:et:sw=12:ts=12:sts=12
|
||||||
|
|
||||||
|
.include "src/mode.S"
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.code16
|
.code16
|
||||||
|
|
||||||
.set SS_CODE16, 0x08
|
|
||||||
.set SS_DATA16, 0x10
|
|
||||||
.set SS_CODE32, 0x18
|
|
||||||
.set SS_DATA32, 0x20
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// _start: entry point
|
// _start: entry point
|
||||||
_start: cli
|
_start: cli
|
||||||
cld
|
cld
|
||||||
|
|
||||||
|
mov %ss, %ax
|
||||||
|
mov %ax, %cs:real_ss
|
||||||
|
|
||||||
|
xor %eax, %eax
|
||||||
|
mov %es, %ax
|
||||||
|
shl $4, %eax
|
||||||
|
movzwl %bx, %ebx
|
||||||
|
add %eax, %ebx
|
||||||
|
mov %ebx, %cs:PXENV
|
||||||
|
|
||||||
|
xor %eax, %eax
|
||||||
|
xor %ebx, %ebx
|
||||||
|
mov %sp, %bx
|
||||||
|
mov %ss:6(%bx), %ax
|
||||||
|
mov %ss:4(%bx), %bx
|
||||||
|
shl $4, %eax
|
||||||
|
add %eax, %ebx
|
||||||
|
mov %ebx, %cs:exPXE
|
||||||
|
|
||||||
mov %sp, %bp
|
mov %sp, %bp
|
||||||
xor %ax, %ax
|
xor %ax, %ax
|
||||||
mov %ax, %ds
|
mov %ax, %ds
|
||||||
mov %ax, %es
|
mov %ax, %es
|
||||||
|
|
||||||
push $msg_start
|
|
||||||
call dbgmsg
|
|
||||||
add $2, %sp
|
|
||||||
|
|
||||||
// initialize our own BSS section
|
// initialize our own BSS section
|
||||||
mov $_bss_start, %di
|
mov $_bss_start, %di
|
||||||
mov $_bss_end, %cx
|
mov $_bss_end, %cx
|
||||||
sub %di, %cx
|
sub %di, %cx
|
||||||
xor %al, %al
|
xor %al, %al
|
||||||
rep stosb
|
rep stosb
|
||||||
|
|
||||||
// a20_enable: Allow use of 'high' (>1Mb) memory
|
// a20_enable: Allow use of 'high' (>1Mb) memory
|
||||||
a20_enable: // Of all the ways to toggle A20, we only try the Fast A20 Gate.
|
a20_enable: // Of all the ways to toggle A20, we only try the Fast A20 Gate.
|
||||||
|
|
@ -36,69 +47,31 @@ 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
|
||||||
|
PROT32
|
||||||
// Set Protection Enable (PE) bit
|
|
||||||
mov %cr0, %eax
|
|
||||||
or $1, %al
|
|
||||||
mov %eax, %cr0
|
|
||||||
|
|
||||||
ljmp $SS_CODE32, $prot_trampo
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
prot_trampo:
|
|
||||||
mov $SS_DATA32, %eax
|
|
||||||
mov %eax, %ds
|
|
||||||
mov %eax, %es
|
|
||||||
mov %eax, %fs
|
|
||||||
mov %eax, %gs
|
|
||||||
mov %eax, %ss
|
|
||||||
|
|
||||||
mov 'Y', %al
|
|
||||||
outb %al, $0xE9
|
|
||||||
|
|
||||||
// TODO load proper stack pointer
|
|
||||||
mov $0x90000, %ebp
|
|
||||||
mov %ebp, %esp
|
|
||||||
|
|
||||||
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 GDT
|
.global PXENV
|
||||||
|
PXENV: .long 0
|
||||||
|
|
||||||
|
.global exPXE
|
||||||
|
exPXE: .long 0
|
||||||
|
|
||||||
|
.global real_ss
|
||||||
|
real_ss: .word 0
|
||||||
|
|
||||||
|
.global GDT
|
||||||
GDT: // entry 0: null descriptor
|
GDT: // entry 0: null descriptor
|
||||||
.space 8, 0
|
.space 8, 0
|
||||||
// entry 1: 16-bit code segment
|
// entry 1: 16-bit code segment
|
||||||
|
|
@ -112,8 +85,6 @@ GDT: // entry 0: null descriptor
|
||||||
// TODO: 32-bit TSS
|
// TODO: 32-bit TSS
|
||||||
.set GDT_SIZE, . - GDT
|
.set GDT_SIZE, . - GDT
|
||||||
GDT_PTR: .word GDT_SIZE - 1
|
GDT_PTR: .word GDT_SIZE - 1
|
||||||
.quad GDT
|
.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"
|
|
||||||
|
|
@ -4,7 +4,7 @@ PHDRS {
|
||||||
}
|
}
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
.text 0x7C00: {
|
.text 0x7C00: {
|
||||||
Rnbp.o(.text)
|
src/nbp.o(.text)
|
||||||
*(.text*, .rodata*)
|
*(.text*, .rodata*)
|
||||||
} :all
|
} :all
|
||||||
.data : {
|
.data : {
|
||||||
|
|
@ -15,7 +15,8 @@ SECTIONS {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
*(.bootboot)
|
bootboot = .;
|
||||||
|
. += 4K;
|
||||||
_bss_end = .;
|
_bss_end = .;
|
||||||
} :all
|
} :all
|
||||||
}
|
}
|
||||||
24
src/pxe.S
Normal file
24
src/pxe.S
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// vim: ft=gas:et:sw=12:ts=12:sts=12
|
||||||
|
|
||||||
|
.include "src/mode.S"
|
||||||
|
|
||||||
|
.data
|
||||||
|
|
||||||
|
pxe_entry: .word 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global pxe_call
|
||||||
|
.code32
|
||||||
|
pxe_call: push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
|
||||||
|
PROT16
|
||||||
|
|
||||||
|
call (pxe_entry)
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
PROT32
|
||||||
|
|
||||||
|
pop %eax
|
||||||
|
leave
|
||||||
|
ret
|
||||||
31
src/std.c
Normal file
31
src/std.c
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#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)
|
||||||
|
:
|
||||||
|
: "cc", "memory");
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
memcmp(const void *src1, const void *src2, size_t n)
|
||||||
|
{
|
||||||
|
__asm__ ("repe cmpsb"
|
||||||
|
: "+D"(src2), "+S"(src1), "+c"(n)
|
||||||
|
:
|
||||||
|
: "cc", "memory");
|
||||||
|
if (n == 0) return 0;
|
||||||
|
return src1 < src2 ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
strlen(const char *s)
|
||||||
|
{
|
||||||
|
size_t l = 0;
|
||||||
|
while (s[l]) l++;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
43
src/std.h
Normal file
43
src/std.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#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);
|
||||||
|
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue