feat(loader): logger print time

This commit is contained in:
d0p1 🏳️‍⚧️ 2024-04-28 08:41:36 +02:00
parent fe5fc658b3
commit fb51cf602a
25 changed files with 796 additions and 14 deletions

View file

@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2020, d0p1
Copyright (c) 2024, d0p1
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -93,6 +93,8 @@ _start:
xor bx, bx
call fat_load_binary
mov dl, [drive_number]
jmp 0x0:LOADER_BASE
.error_not_found:

View file

@ -3,6 +3,8 @@
include '../common/const.inc'
include '../common/macro.inc'
include '../common/bios.inc'
include '../common/mbr.inc'
org MBR_BASE
cli
@ -19,9 +21,60 @@
rep movsw
jmp 0x0:start
start:
; TODO: read partition table and load bootable one.
; set LBA
mov ah, 0x41
mov bx, 0x55AA
mov dl, 0x80
int 0x13
jc .error_lba
lea ecx, [PT1]
.loop:
mov al, byte [ecx]
bt ax, 7
jc .found
lea eax, [PT4]
test eax, ecx
je .error_no_bootable
add cx, 0xF
jmp .loop
.found:
mov eax, dword [ecx + Partition.lba]
mov [disk_packet_lba], eax
mov si, disk_packet
mov ah, 0x42
mov dl, 0x80
int 13
jc .error_load
jmp 0x0:BOOTSECT_BASE
.error_lba:
mov si, msg_error_lba
jmp .error_print
.error_no_bootable:
mov si, msg_error_bootable
jmp .error_print
.error_load:
mov si, msg_error_load
.error_print:
call bios_print
.end:
hlt
jmp $
times 436-($-$$) db 0x90
disk_packet:
db 0x10
db 0
dw 1
dw BOOTSECT_BASE
dw 0x0
disk_packet_lba:
dd 0x0
dw 0x0
msg_error_lba db "We don't support CHS", CR, LF, 0
msg_error_bootable db "No bootable device found", CR, LF, 0
msg_error_load db "Can't load partition", CR, LF, 0
rb MBR_BASE+0x1a8-$
UID db 'STUPIDDISK'
; partition table
PT1 db 16 dup(0)

View file

@ -10,6 +10,9 @@ DISK_BUFFER = 0x8000
KERNEL_PRELOAD = 0xF000
STACK_TOP = 0x7000
; ---------- Magic ------------
STPDBOOT_MAGIC = 0x53545044
; ---------- Video ------------
VIDEO_WIDTH = 1024
VIDEO_HEIGHT = 768

15
boot/common/mbr.inc Normal file
View file

@ -0,0 +1,15 @@
;; File: mbr.inc
struc Partition
{
.status db ?
.chs_start db 3 dup(?)
.type db ?
.chs_last db 3 dup(?)
.lba dd ?
.sectors dd ?
}
defn Partition

View file

@ -50,3 +50,4 @@ Section: UEFI (IA32)
> | BOOTIA32.EFI |----->| vmstupid.sys |
> +--------------+ +--------------+
>

View file

@ -2,6 +2,9 @@ TARGET = stpdldr.sys
LOADER_SRCS = loader.asm \
../common/const.inc \
video.inc \
memory.inc \
logger.inc \
a20.inc \
multiboot.inc

View file

@ -27,20 +27,41 @@ _start:
push cs
pop ds
mov [drive_number], dl
mov si, msg_stage2
call bios_print
call bios_log
; enable A20 line
call a20_enable
jc .error_a20
; check drive type
; dl <= 0x7F == floppy
; dl >= 0x80 == hard drive
; dl == 0xE0 ~= CD/DVD
; dl <= 0xFF == hard drive
mov dl, [drive_number]
cmp dl, 0x7F
; skip disk extension check
jle @f
; check disk extensions
mov ah, 0x41
mov bx, 0x55AA
int 0x13
jc @f
mov [drive_lba], 1
@@:
; detect filesystem (FAT12/16 or StpdFS)
; load kernel from filesystem
; fetch memory map from bios
call memory_get_map
jc .error_memory
; video information
call video_setup
xchg bx, bx
; load GDT and enter Protected-Mode
lgdt [gdt_ptr]
@ -65,21 +86,26 @@ _start:
.error_a20:
mov si, msg_error_a20
.error:
call bios_print
call bios_log
@@:
hlt
jmp @b
include 'a20.inc'
include '../common/bios.inc'
include 'logger.inc'
include 'memory.inc'
include 'video.inc'
include 'gdt.inc'
msg_stage2 db "StupidOS Loader", CR, LF, 0
drive_number rb 1
drive_lba db 0
msg_stage2 db "StupidOS Loader", 0
kernel_fat12_file db "VMSTUPIDSYS", 0
msg_error_a20 db "ERROR: can't enable a20 line", CR, LF, 0
msg_error_memory db "ERROR: can't detect available memory", CR, LF, 0
config_fat12_file db "BOOT INI", 0
msg_error_a20 db "ERROR: can't enable a20 line", 0
msg_error_memory db "ERROR: can't detect available memory", 0
use32
; =========================================================================
@ -101,6 +127,10 @@ common32:
; identity map first 1MB
; map kernel to 0xC0000000
push STPDBOOT_MAGIC
mov eax, 0xC0000000
jmp eax
hang:
hlt
jmp $

54
boot/loader/logger.inc Normal file
View file

@ -0,0 +1,54 @@
bios_log_time:
clc
mov ah, 0x02
int 0x1A
mov al, ch
aam
add ah, 0x30
add al, 0x30
mov [time + 1], ah
mov [time + 2], al
mov al, cl
aam
add ah, 0x30
add al, 0x30
mov [time + 4], ah
mov [time + 5], al
mov al, dh
aam
add ah, 0x30
add al, 0x30
mov [time + 7], ah
mov [time + 8], al
mov si, time
call bios_print
ret
bios_log_hex:
ret
;; Function: bios_log
;;
;; Parameters:
;; SI - string to print
;; [STACK] - variadic arguments
;;
bios_log:
push si
call bios_log_time
pop si
call bios_print
mov si, endline
call bios_print
ret
time db '[00:00.00] ', 0
endline db CR, LF, 0

View file

@ -65,6 +65,9 @@ memory_e820_get_map:
;; BX - Extended 2
;; CX - Configured 1
;; DX - Configured 2
memory_get_for_large_conf:
mov ax, 0xE801
int 0x15
;; Function: memory_get_extended_memory_size
;;
@ -75,4 +78,5 @@ memory_e820_get_map:
;; CF - Non-Carry - indicates no error
;; AX - Number of contiguous KB above 1MB
memory_get_map:
clc
ret

View file

@ -82,6 +82,7 @@ struc MultibootData
.fb_type db ?
.fb_misc dw 3 dup ?
}
defn MultibootData
MULTIBOOT_DATA_MEM = 0x0001
MULTIBOOT_DATA_BOOTDEV = 0x0002
@ -100,6 +101,7 @@ struc MultibootMMap
.length dq ?
.type dd ?
}
defn MultibootMMap
MULTIBOOT_MEMORY_AVAILABLE = 0x1
MULTIBOOT_MEMORY_RESERVED = 0x2
@ -114,3 +116,4 @@ struc MultibootModule
.cmdline dd ?
.pad dd ?
}
defn MultibootModule

View file

@ -14,6 +14,7 @@ struc VesaInfo
.Reserved db 222 dup(?)
.OEMData db 256 dup(?)
}
defn VesaInfo
struc VesaModeInfo
{
@ -59,4 +60,29 @@ struc VesaModeInfo
defn VesaModeInfo
video_setup:
clc
mov di, [vesa_block_buffer]
mov ax, 0x4F00
int 0x10
cmp ax, 0x004F
jne .err
push word [vesa_block_buffer + VesaInfo.VideoModesSegment]
pop es
mov di, vesa_info_block_buffer
mov bx, [vesa_block_buffer + VesaInfo.VideoModesOffset]
mov cx, [bx]
cmp cx, 0xFFFF
je .err
mov ax, 0x4F01
int 0x10
cmp ax, 0x004F
jne .err
ret
.err:
stc
ret
vesa_block_buffer VesaInfo
vesa_info_block_buffer VesaModeInfo

View file

@ -2,6 +2,8 @@
# define ECHFS_H 1
typedef struct {
uint8_t jmp[4];
uint8_t signature[8];
} EchFSIdentityTable;

View file

@ -8,7 +8,15 @@
include 'mm/mm.inc'
;; Function: kmain
;;
;; Parameters:
;;
;; EAX - Boot Magic
;; EBX - Boot structure address
;;
kmain:
; TODO: interupt, vmm
nop
_edata:

View file

@ -1,6 +1,4 @@
free_block_head dd 0x0
mm_init:
ret
ret

View file

@ -1,4 +1,4 @@
SUBDIRS = csu crypto lzp
SUBDIRS = csu crypto lzp c
TOPGOALS = all clean install

20
lib/c/Makefile Normal file
View file

@ -0,0 +1,20 @@
TARGET = libc.a
OBJS = ctype.o
INCS = stddef.h time.h ctype.h
all: $(TARGET)
$(TARGET): $(OBJS)
$(AR) rcs $@ $^
%.o: %.asm
$(AS) $< $@
clean:
$(RM) $(TARGET) $(OBJS)
install: $(TARGET)
@ mkdir -p $(DESTDIR)$(LIBDIR)
install $(TARGET) $(DESTDIR)$(LIBDIR)
@ mkdir -p $(DESTDIR)$(INCDIR)
install $(INCS) $(DESTDIR)$(INCDIR)

34
lib/c/ctype.asm Normal file
View file

@ -0,0 +1,34 @@
format COFF
use32
public isdigit
section '.code' code
;; Function: isdigit
;;
;; Parameters:
;;
;; [esp+8] - character
;;
;; Returns:
;;
;; eax - 1 if digit otherwhise 0
;;
isdigit:
push ebp
mov ebp, esp
mov al, '0'
mov cl, byte [esp+8]
cmp al, cl
jb @f
mov al, '9'
cmp al, cl
jg @f
mov eax, 1
jmp .end
@@:
xor eax, eax
.end:
leave
ret

7
lib/c/ctype.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef CTYPE_H
# define CTYPE_H 1
int isalnum(int c);
int isdigit(int c);
#endif /* !CTYPE_H */

6
lib/c/stddef.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef STDDEF_H
# define STDDEF_H 1
typedef unsigned int size_t;
#endif /* !STDDEF_H */

31
lib/c/time.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef TIME_H
# define TIME_H 1
# include <stdint.h>
/* POSIX define CLOCKS_PER_SEC as on milion */
# define CLOCKS_PER_SEC 1000000
typedef int64_t time_t;
typedef uint64_t clock_t;
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
double difftime(time_t time_end, time_t time_beg);
time_t time(time_t *arg);
clock_t clock(void);
char *asctime(const struct tm *time); /* fuck modern C */
char *ctime(const time_t *timer);
size_t strftime(char *str, size_t count, const char *format, const struct tm *tp);
#endif /* !TIME_H */

175
sbin/mkfs.stpd/main.c Normal file
View file

@ -0,0 +1,175 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#define MAGIC 0x44505453
#define BLOCK_SIZE 512
struct superblock {
uint32_t magic;
uint32_t isize;
uint32_t fsize;
uint32_t free[100];
uint8_t nfree;
uint8_t flock;
uint8_t ilock;
uint8_t fmod;
uint32_t time[2];
} __attribute__((packed));
struct inode {
uint16_t mode;
uint8_t nlink;
uint8_t uid;
uint8_t gid;
uint32_t size;
uint16_t addr[8];
uint32_t actime[2];
uint32_t modtime[2];
} __attribute__((packed));
#define INODE_SIZE sizeof(struct inode)
struct file {
unsigned short inode;
char filename[14];
};
static const char *prg_name = NULL;
static int verbose = 0;
static const char *device = NULL;
static int devfd = 0;
static off_t device_size = 0;
static int
write_sector(size_t secnum, const uint8_t *data, size_t buff_size)
{
uint8_t buffer[BLOCK_SIZE];
if (lseek(devfd, secnum * BLOCK_SIZE, SEEK_SET) != (secnum * BLOCK_SIZE))
{
fprintf(stderr, "%s: %s\n", device, strerror(errno));
exit(EXIT_FAILURE);
}
memset(buffer, 0, BLOCK_SIZE);
memcpy(buffer, data, buff_size);
if (write(devfd, buffer, BLOCK_SIZE) != BLOCK_SIZE)
{
fprintf(stderr, "%s: x %s\n", device, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void
usage(int retcode)
{
if (retcode == EXIT_FAILURE)
{
fprintf(stderr, "Try '%s -h' for more informations.\n", prg_name);
}
else
{
printf("Usage: %s [-hVv] disk\n", prg_name);
printf("\t-h\tdisplay this help and exit\n");
printf("\t-V\toutput version information.\n");
printf("\nReport bugs to <%s>\n", MK_BUGREPORT);
}
exit(retcode);
}
static void
version(void)
{
printf("%s commit %s\n", prg_name, MK_COMMIT);
exit(EXIT_SUCCESS);
}
int
main(int argc, char **argv)
{
struct stat inf;
int idx;
uint8_t buffer[BLOCK_SIZE];
struct superblock sb;
prg_name = argv[0];
while ((argc > 1) && (argv[1][0]) == '-')
{
switch (argv[1][1])
{
case 'h':
usage(EXIT_SUCCESS);
break;
case 'V':
version();
break;
case 'v':
verbose=1;
break;
default:
usage(EXIT_FAILURE);
}
argv++;
argc--;
}
if (argc <= 1) usage(EXIT_FAILURE);
device = argv[1];
if (stat(device, &inf) != 0)
{
fprintf(stderr, "%s: %s\n", device, strerror(errno));
return (EXIT_FAILURE);
}
device_size = inf.st_size;
if (verbose) printf("Device size: %ld (%ld blocks)\n", device_size, device_size/BLOCK_SIZE);
/*if (device_size/BLOCK_SIZE > 0x7fff)
{
fprintf(stderr, "%s: File too large\n", device);
return (EXIT_FAILURE);
}*/
/* */
devfd = open(device, O_WRONLY);
if (devfd < 0)
{
fprintf(stderr, "%s: %s\n", device, strerror(errno));
return (EXIT_FAILURE);
}
memset(buffer, 0, BLOCK_SIZE);
for (idx = 0; idx < device_size/BLOCK_SIZE; idx++)
{
write_sector(idx, buffer, BLOCK_SIZE);
}
if (verbose) printf("Write %ld (%ld bytes)\n", device_size/BLOCK_SIZE, device_size);
memset(&sb, 0, sizeof(struct superblock));
sb.magic = MAGIC;
sb.fsize = device_size/BLOCK_SIZE;
write_sector(1, (uint8_t *)&sb, sizeof(struct superblock));
//sb.ninode = (device_size/BLOCK_SIZE) / 8;
printf("sizeof %lu %lu\n", sizeof(struct superblock), sizeof(struct inode));
close(devfd);
return (EXIT_SUCCESS);
}

304
sbin/mkfs.stpd/v6.5 Normal file
View file

@ -0,0 +1,304 @@
V6/usr/man/man5/fs.5
Compare this file to the similar file:
Show the results in this format:
.TH "FILE SYSTEM" V 2/9/75
.SH NAME
fs \*- format of file system volume
.SH DESCRIPTION
Every
file system storage volume
(e.g. RF disk, RK disk, RP disk, DECtape reel)
has a common format for certain vital information.
Every such volume is divided into a certain number
of 256 word (512 byte) blocks.
Block 0 is unused and is available to contain
a bootstrap program, pack label, or other information.
.s3
Block 1 is the
.IB "super block."
Starting from its first word, the format of a super-block is
.s3
.nf
struct {
int isize;
int fsize;
int nfree;
int free[100];
int ninode;
int inode[100];
char flock;
char ilock;
char fmod;
int time[2];
};
.s3
.fi
.IP Isize
is the number of blocks devoted to the i-list,
which starts just after the super-block, in block 2.
.IP Fsize
is the first block not potentially available for allocation
to a file.
These numbers are used by the system to
check for bad block numbers;
if an ``impossible'' block number is allocated from the free list
or is freed,
a diagnostic is written on the on-line console.
Moreover, the free array is cleared, so as to prevent further
allocation from a presumably corrupted free list.
.s3
The free list for each volume is maintained as
follows.
The
.IB free
array contains, in
.IB "free[1], ... , free[nfree\*-1],"
up to 99 numbers of free blocks.
.IB Free[0]
is the block number of the head
of a chain of blocks constituting the free list.
The first word in each free-chain block is the number
(up to 100) of free-block numbers listed in the
next 100 words of this chain member.
The first of these 100 blocks is the link to the
next member of the chain.
To allocate a block:
decrement
.IB nfree,
and the new block is
.IB free[nfree].
If the new block number is 0,
there are no blocks left, so give an error.
If
.IB nfree
became 0,
read in the block named by the new block number,
replace
.IB nfree
by its first word,
and copy the block numbers in the next 100 words into the
.IB free
array.
To free a block, check if
.IB nfree
is 100; if so,
copy
.IB nfree
and the
.IB free
array into it,
write it out, and set
.IB nfree
to 0.
In any event set
.IB free[nfree]
to the freed block's number and
increment
.IB nfree.
.s3
.IB Ninode
is the number of free i-numbers in the
.IB inode
array.
To allocate an i-node:
if
.IB ninode
is greater than 0,
decrement it and return
.IB inode[ninode].
If it was 0, read the i-list
and place the numbers of all free inodes
(up to 100) into the
.IB inode
array,
then try again.
To free an i-node,
provided
.IB ninode
is less than 100,
place its number into
.IB inode[ninode]
and increment
.IB ninode.
If
.IB ninode
is already 100, don't bother to enter the freed i-node into any table.
This list of i-nodes is only to speed
up the allocation process; the information
as to whether the inode is really free
or not is maintained in the inode itself.
.s3
.IB Flock
and
.IB ilock
are flags maintained in the core
copy of the file system
while it is mounted
and their values on disk are immaterial.
The value of
.IB fmod
on disk is likewise immaterial;
it is used as a flag to indicate that the super-block has
changed and should be copied to
the disk during the next periodic update of file
system information.
.s3
.IB Time
is the last time the super-block of the file system was changed,
and is a double-precision representation
of the number of seconds that have elapsed
since
0000 Jan. 1 1970 (GMT).
During a reboot, the
.IB time
of the super-block for the root file system
is used to set the system's idea of the time.
.s3
I-numbers begin at 1, and the storage for i-nodes
begins in block 2.
.tr |
Also, i-nodes are 32 bytes long, so 16 of them fit into a block.
Therefore, i-node
.IB i
is located in block (\fIi\fR|+|31)|/|16, and begins
32\u\fB.\fR\d((\fIi\fR|+|31)|(mod 16) bytes from its start.
I-node 1 is reserved for the root directory of the file
system, but no other i-number has a built-in
meaning.
Each i-node represents one file.
The format of an i-node is as follows.
.s3
.nf
.if t .ta .5i 1.i 2.5i
struct {
int flags; /* +0: see below */
char nlinks; /* +2: number of links to file */
char uid; /* +3: user ID of owner */
char gid; /* +4: group ID of owner */
char size0; /* +5: high byte of 24-bit size */
int size1; /* +6: low word of 24-bit size */
int addr[8]; /* +8: block numbers or device number */
int actime[2]; /* +24: time of last access */
int modtime[2]; /* +28: time of last modification */
};
.dt
.fi
.s3
The flags are as follows:
.s3
.lp +10 9
100000 i-node is allocated
.lp +10 9
060000 2-bit file type:
.lp +15 9
000000 plain file
.lp +15 9
040000 directory
.lp +15 9
020000 character-type special file
.lp +15 9
060000 block-type special file.
.lp +10 9
010000 large file
.lp +10 9
004000 set user-ID on execution
.lp +10 9
002000 set group-ID on execution
.lp +10 9
000400 read (owner)
.lp +10 9
000200 write (owner)
.lp +10 9
000100 execute (owner)
.lp +10 9
000070 read, write, execute (group)
.lp +10 9
000007 read, write, execute (others)
.s3
.i0
Special files are recognized by their flags
and not by i-number.
A block-type special file is basically one which
can potentially be mounted as a file system;
a character-type special file cannot, though it is
not necessarily character-oriented.
For special files the high byte of the first address word
specifies the type of device; the low byte specifies
one of several devices of
that type.
The device type numbers
of block and character special files overlap.
.s3
The address words of ordinary files and directories
contain the numbers of the blocks in the
file (if it is small)
or the numbers of indirect blocks (if the file
is large).
Byte number
.IB n
of a file is accessed as follows.
.IB N
is divided by 512 to find its logical block number
(say
.IB b
)
in the file.
If the file is small (flag 010000 is 0),
then
.IB b
must be less than 8, and the physical
block number is
.IB addr[b].
.s3
If the file is large,
.IB b
is divided by 256 to yield
.IB i.
If
.IB i
is less than 7, then
.IB addr[i]
is the physical block number of
the indirect block.
The remainder from the division
yields the word in the indirect block
which contains the number of the block for
the sought-for byte.
.s3
If
.IB i
is equal to 7,
then the file has become extra-large (huge),
and
.IB addr[7]
is the address of a first indirect block.
Each word in this block
is the number of a second-level indirect block;
each word in the second-level indirect blocks points to a data block.
Notice that extra-large files are not marked by any mode
bit, but only by having
.IB addr[7]
non-zero;
and that although this scheme allows for more than
256\*X256\*X512 = 33,554,432 bytes per file,
the length of files is stored in 24 bits
so in practice a file can be at most
16,777,216 bytes long.
.s3
For block
.IB b
in a file to exist,
it
is not necessary that all blocks less than
.IB b
exist.
A zero block number either in the address words of
the i-node or in an indirect block indicates that the
corresponding block has never been allocated.
Such a missing block reads as if it contained all zero words.
.SH "SEE ALSO"
icheck, dcheck (VIII)

View file

@ -1,7 +1,7 @@
CC = gcc
RM = rm -f
TARGET = fat$(EXEXT) coff-ld$(EXEXT) parted$(EXEXT)
TARGET = fat$(EXEXT) coff-ld$(EXEXT) parted$(EXEXT) mkfs.stpd$(EXEXT)
CFLAGS = -DMK_COMMIT="$(MK_COMMIT)" -DMK_BUGREPORT="$(MK_BUGREPORT)" -I../include
LDFLAGS =
@ -18,6 +18,9 @@ coff-ld$(EXEXT): coff-ld.c
parted$(EXEXT): ../sbin/parted/main.c
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
mkfs.stpd$(EXEXT): ../sbin/mkfs.stpd/main.c
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
.PHONY: install
install: $(TARGET)