Compare commits

...

10 Commits

Author SHA1 Message Date
06160c1ed3 add disk read
not implementing disk write yet
2024-12-16 23:23:18 +09:00
14fac398c5 add disk info interrupt 2024-12-12 17:25:00 +09:00
O_WRONLY
bc671ff92b
Merge pull request #1 from Hojun-Cho/fix-fmt
fix fmt,print
2024-12-12 17:24:26 +09:00
8ad0446359 fix fmt,print
for easy to use fmtinstall
2024-12-12 17:22:49 +09:00
e74cf22714 add heap alloc function
Physically contiguous memory
2024-12-12 14:08:01 +09:00
O_WRONLY
a9a1ad666d
Update README.md 2024-12-10 23:50:23 +09:00
Hojun-Cho
98601ac381 add CPUID probe
Just print vendor, Hypervisor...
2024-12-09 21:28:45 +09:00
b1f7092fe2 add fmt.c for print function
don't process 64-bit format such as '%llu' in print function.
2024-12-09 15:43:58 +09:00
c9c820840f add memprobe
NOTE: print "%llx" "%lld" not working now
2024-12-08 23:14:32 +09:00
8336f11b2a fix protection fault from GDT 2024-12-07 01:14:26 +09:00
12 changed files with 861 additions and 93 deletions

View File

@ -1,6 +1,10 @@
# FAT16 bootloader
x86 FAT16 bootloader
# Feature
* [serial console](https://github.com/Hojun-Cho/bootloader/blob/master/boot/sricon.c)
* [prompt](https://github.com/Hojun-Cho/bootloader/blob/98601ac381e30d98b4f3f2c20a733beebf9c2ee3/boot/boot.c#L105)
### How to run
1. install image to device
install to device
@ -32,4 +36,4 @@
1. set Global Descriptor Table
2. enter protected mode
2. set Interrupt Descriptor Table
3. call boot function
3. call boot function

View File

@ -5,7 +5,7 @@ PROG = boot
SRCS = srt0.S gdt.S boot.c
OBJS = srt0.o gdt.o boot.o
ESRCS = pccon.c sricon.c print.c a20.c time.c
ESRCS = pccon.c sricon.c print.c fmt.c a20.c time.c mem.c cpu.c alloc.c disk.c
OBJS += $(ESRCS:.c=.o)
include $(SDIR)/Makefile.inc

67
boot/alloc.c Normal file
View File

@ -0,0 +1,67 @@
#include <u.h>
#include "dat.h"
#include "fn.h"
// only for booting
typedef struct FreeList FreeList;
static struct FreeList{
uint size;
FreeList *next;
} *freed;
extern char end[];
static char *top = end;
static void
putfreed(FreeList *p)
{
p->next = nil;
if(freed){
p->next = freed;
freed = p;
}else
freed = p;
}
static FreeList*
getfreed(uint n)
{
for(FreeList *p=freed,*l=freed; p; p=p->next){
if(p->size >= n){
l->next = p->next;
if(p == freed)
freed = nil;
return p;
}
l = p;
}
return nil;
}
void*
alloc(uint n)
{
FreeList *p;
p = getfreed(n);
if(p == nil){
p = (FreeList*)top;
p->size = n;
p->next = nil;
memset(p+sizeof(*p), 0, n);
top += n + sizeof(*p);
}
if(debug) print("alloc %x %ud\n", &p[1], n);
return &p[1];
}
void
free(void *src)
{
FreeList *p;
p = (FreeList*)((char*)src-sizeof(FreeList));
if(debug) print("free %x %ud\n", src, p->size);
putfreed(p);
}

View File

@ -6,9 +6,11 @@ static void coninit(void);
static void machdep(void);
void (*probe1[])(void) = {
a20up, coninit,
a20up, coninit, memprobe,
cpuidprobe,
};
void (*probe2[])(void) = {
diskprobe,
};
BootProbe probes[] = {
@ -31,7 +33,11 @@ ConDev contab[CON_END] = {
.init = cominit,
},
};
ConDev *con = &contab[0];
BIOSmmap biosmmap[64];
uint cnvmem, extmem;
int debug = BOOT_DEBUG;
static void
coninit(void)
@ -92,9 +98,14 @@ done:
void
boot(int bootdev)
{
print("\n\n===> Hello world <===\n\tBooted on disk 0x%x\n", bootdev);
machdep();
BIOSdisk d = {0,};
fmtinstall('D', fmtdisk);
print("\n===> Hello world <===\n\t"
"Booted on disk 0x%x debug:%d\n\t", bootdev, debug);
machdep();
bdiskget(bootdev, &d);
for(;;){
char buf[8192];

56
boot/cpu.c Normal file
View File

@ -0,0 +1,56 @@
#include <u.h>
#include "dat.h"
#include "fn.h"
#define EFLAG_ID 0x00200000
#define CPUID(code, a, b, c, d) \
__asm volatile("cpuid" \
: "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
: "a" (code))
void*
memset(void *dst, int v, int l)
{
char *p = dst;
for(int i = 0; i < l; ++i)
*p++ = 0;
return dst;
}
void
cpuidprobe(void)
{
int canuse;
union{
struct{u32 a,b,d,c;};
char arr[16];
}r = {0,};
__asm volatile("pushfl\n\t"
"popl %2\n\t"
"xorl %2, %0\n\t" /* Invert ID sotred in EFLAGS */
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"xorl %2, %0\n\t"
: "=r" (canuse)
: "0" (EFLAG_ID), "r" (0) /* "EFLAGS_ID" same location "canuse" */
: "cc");
if(canuse != EFLAG_ID){
print("cpuid not available\n");
return;
}
// print vendor
CPUID(0x00, r.a, r.b, r.c, r.d);
print("CPU vender: %s\n", r.arr+4);
// Is running on Hypervisor?
// But nothing to do...
memset(&r, 0,sizeof(r));
CPUID(0x01, r.a, r.b, r.c, r.d);
if(r.c & (1<<31)){
CPUID(1<<30, r.a, r.b, r.c, r.d);
print("Running on Hypervisor: %s\n", r.arr+4);
}
}

View File

@ -2,6 +2,13 @@
// 0x60 Read/Write Data Port
// 0x64 Read Status Register
// 0x64 Write Command Register
#define TABWIDTH 8
#ifndef BOOT_DEBUG
#define BOOT_DEBUG 1
#endif
#define DOSPARTOFF 446
#define NDOSPART 4
enum{
CON_PC,
@ -36,6 +43,63 @@ struct ConDev{
uint dev;
uchar pri; // the higher the better
};
typedef struct{
u64 addr; /* Beginning of block */
u64 size; /* Size of block */
u32 type; /* Type of block */
} __attribute__((packed)) BIOSmmap;
// fmt.c
typedef struct{
int ucase;
int padch;
char *p;
char *ep;
int f1, f2, f3;
va_list ap;
}Op;
// disk.c
typedef struct{
u8 flag; /* bootstrap flags */
u8 bhd; /* begin head */
u8 bsec; /* begin sector */
u8 bcyl; /* begin cylinder */
u8 type; /* partition type (see below) */
u8 ehd; /* end head */
u8 esec; /* end sec2r */
u8 ecyl; /* end cylinder */
u32 beg; /* absolute starting sectoff number */
u32 size; /* partition size in sec2rs */
} __attribute__((packed)) DOSpart;
typedef struct{
u8 boot[DOSPARTOFF];
DOSpart parts[NDOSPART];
u16 sign;
} __attribute__((packed)) DOSmbr;
typedef struct{
int n;
u32 ncyl;
u32 nhead;
u32 nsec;
i32 edd;
u32 dev ;
u32 checksum;
u32 flag;
} __attribute__((packed)) BIOSdisk;
typedef struct{
}Disklabel;
typedef struct{
BIOSdisk bdsk; // bios disk info
Disklabel label;
int bootdev, osdev;
}Disk;
// gdt.S
extern volatile struct BIOSreg BIOSreg;
@ -44,5 +108,8 @@ extern volatile struct BIOSreg BIOSreg;
extern void (*probe1[])(void);
extern void (*probe2[])(void);
extern BootProbe probes[];
extern BIOSmmap biosmmap[64];
extern ConDev contab[CON_END];
extern ConDev *con;
extern uint cnvmem, extmem;
extern int debug;

174
boot/disk.c Normal file
View File

@ -0,0 +1,174 @@
#include <u.h>
#include "dat.h"
#include "fn.h"
#define BDA_DISK 0x0475 // of hard disk drives detected
#define MAX_DISK_ENTRY 1 // for now
enum{
Bread = 0x4200,
Bwrite = 0x4300,
};
// interrupt 41h exension support bitmap
enum{
Eeda = 0x01, // Extended disk access funcions 42-44,47,48
Erdc = 0x02, // removable drive controller functions 45,46,48,49
Eedd = 0x04, // Enhanced disk drive functions
};
typedef struct{
u8 len;
u8 res1;
u8 nblk;
u8 res2;
u16 off;
u16 seg;
u64 daddr; // starting block
}EDDcb;
Disk disks[MAX_DISK_ENTRY];
static int
ireset(int dev)
{
int rv;
__asm volatile("int $0x33\n\t"
"setc %b0"
: "=a" (rv)
: "0" (0), "d" (dev)
: "%ecx", "%cc");
return (rv&0xff) ? -1 : 0;
}
// Bit(s) Description (Table 00271)
// 0 extended disk access functions (AH=42h-44h,47h,48h) supported
// 1 removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
// 2 enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported.
// Extended drive parameter table is valid (see #00273,#00278)
// 3-15 reserved (0)
static __inline int
ieddsuport(BIOSdisk *d)
{
int bmap, rv;
__asm volatile("int $0x33\n\t"
"setc %b0"
: "=a" (rv), "=c" (bmap)
: "0" (0x4100), "b" (0x55aa), "d" (d->n)
: "cc");
if(rv&0xff || (BIOSreg.bx&0xffff) != 0xaa55)
return -1;
d->edd = (bmap&0xffff) | ((rv&0xff)<<16);
return 0;
}
static __inline int
bdiskinfo(BIOSdisk *d)
{
int rv;
// CL = maximum sector number (bits 5-0)
// high two bits of maximum cylinder number (bits 7-6)
__asm volatile("int $0x33\n\t"
"setc %b0\n\t"
"movzbl %h1, %1\n\t"
"movzbl %%cl, %3; andb $0x3f, %b3\n\t"
"xchgb %%cl, %%ch; rolb $2, %%ch"
: "=a" (rv), "=d" (d->nhead), "=c" (d->ncyl), "=b" (d->nsec)
: "0" (0x0800), "1" (d->n)
: "cc");
return (rv&0xff) == 0 ? 0 : -1;
}
int
bdiskget(int dev, BIOSdisk *d)
{
if(ireset(dev)){
print("Can't reset disk\n");
return -1;
}
d->n = dev;
if(bdiskinfo(d)){
print("Can't read disk\n");
return -1;
}
if(ieddsuport(d)){
print("edd not supported\n");
return -1;
}
return 0;
}
static int
diskrw(uint rw, int dev, u32 daddr, u32 blk, void *buf)
{
int rv;
volatile EDDcb cb = {0,};
cb.len = sizeof(cb);
cb.nblk = blk;
cb.seg = ((u32)buf>>4 & 0xffff);
cb.off = (u32)buf & 0xf;
cb.daddr = daddr;
if(cb.seg==0 || cb.off==0)
return -1;
BIOSreg.ds = (u32)&cb >> 4;
__asm volatile ("int $0x33\n\t"
"setc %b0\n\t"
: "=a" (rv)
: "0" (rw), "d" (dev), "S" ((int)(&cb)&0xf)
: "%ecx", "cc");
return rv&0xff? -1 : 0;
}
static int
findos(BIOSdisk *bd)
{
DOSmbr mbr = {0,};
if(diskrw(Bread, bd->n, 0, 1, &mbr)){
print("Can't find os disk %d\n", bd->n);
return -1;
}
print("found os disk signature: 0x%x\n", mbr.sign);
return 0;
}
static int
findlabel(BIOSdisk *b, Disklabel *dl)
{
if(b->n & 0x80){
findos(b);
return 0; // for now
}
print("Can't found disk label:%x \n", b->n);
return -1;
}
void
diskprobe(void)
{
int n = MIN((int)*(char*)BDA_DISK, MAX_DISK_ENTRY);
for(int i = 0x80; i < 0x80+n; ++i){
if(bdiskget(i, &disks[i].bdsk))
return;
print("Disnk info: %D\n", disks[i].bdsk);
if(findlabel(&disks[i].bdsk, &disks[i].label)){
}
}
}
int
fmtdisk(Op *op)
{
dofmt(op, "disk:%x cyl:%d head:%d sec:%d edd:%d");
// for skip va_list
USED(va_arg(op->ap, u32));
USED(va_arg(op->ap, u32));
USED(va_arg(op->ap, u32));
return 0;
}

304
boot/fmt.c Normal file
View File

@ -0,0 +1,304 @@
#include <u.h>
#include "dat.h"
#include "fn.h"
#define MAXCON 30
#define IDIGIT 30
enum{
FLONG = (1<<0),
FSHORT = (1<<2),
FUNSIGN = (1<<3),
};
static void put(Op*, int);
static int noconv(Op*);
static int cconv(Op*);
static int dconv(Op*);
static int hconv(Op*);
static int lconv(Op*);
static int sconv(Op*);
static int uconv(Op*);
static int xconv(Op*);
static int Xconv(Op*);
static int percent(Op*);
static int (*fmtconv[MAXCON])(Op*) = {
noconv,
cconv, dconv, hconv, lconv,
sconv, uconv, xconv, Xconv,
percent,
};
int fmtindex[128] = {
['c'] = 1,
['d'] = 2,
['h'] = 3,
['l'] = 4,
['s'] = 5,
['u'] = 6,
['x'] = 7,
['X'] = 8,
['%'] = 9,
};
int convcnt = 11;
int
strlen(char *s)
{
char *p = s;
while(*p)
++p;
return p-s;
}
int
fmtinstall(int c, int (*f)(Op*))
{
c &= 0177;
if(fmtindex[c] == 0){
if(convcnt + 1 >= MAXCON)
return -1;
fmtindex[c] = convcnt++;
}
fmtconv[fmtindex[c]] = f;
return 0;
}
char*
dofmt(Op *op, char *fmt)
{
int sf1, c;
while(1){
c = *fmt++;
if(c != '%'){
if(c == 0){
if(op->p < op->ep)
*op->p = 0;
return op->p;
}
put(op, c);
continue;
}
op->f2 = -1;
op->f1 = op->f3 = 0;
op->padch = sf1 = 0;
c = *fmt++;
if(c == '-'){
sf1 = 1;
c = *fmt++;
}else if(c == '0' || c == ' '){
op->padch = c;
c = *fmt++;
}
while(c >= '0' && c <= '9'){
op->f1 = op->f1*10 + c-'0';
c = *fmt++;
}
if(sf1)
op->f1 = -op->f1;
if(c != '.')
goto conv;
c = *fmt++;
while(c >= '0' && c <= '9'){
if(op->f2 < 0)
op->f2 = 0;
op->f2 = op->f2*10 + c-'0';
c = *fmt++;
}
conv:
if(c == 0)
fmt -= 1;
c = (*fmtconv[fmtindex[c&0177]])(op);
if(c < 0){
op->f3 |= -c;
c = *fmt++;
goto conv;
}
}
}
static void
strconv(char *s, Op *op, int f1, int f2)
{
int n, c;
char *p;
n = strlen(s);
if(f1 >= 0)
while(n < f1){
put(op, op->padch);
n += 1;
}
for(p=s; (c = *p++);)
if(f2){
put(op, c);
f2 -= 1;
}
if(f1 < 0){
f1 = -f1;
while(n < f1){
put(op, ' ');
n += 1;
}
}
}
static void
numconv(Op *op, int base)
{
char b[IDIGIT];
int i,f,n;
long v;
short h;
i = IDIGIT-1;
f = 0;
b[i] = 0;
switch(op->f3 & (FLONG|FSHORT|FUNSIGN)){
case FLONG:
v = va_arg(op->ap, long);
break;
case FUNSIGN|FLONG:
v = va_arg(op->ap, ulong);
break;
case FSHORT:
v = h = va_arg(op->ap, short);
break;
case FUNSIGN|FSHORT:
h = va_arg(op->ap, ushort);
v = (ushort)h;
break;
case FUNSIGN:
v = va_arg(op->ap, unsigned);
break;
default:
v = va_arg(op->ap, int);
break;
}
if((op->f3 & FUNSIGN) && v < 0){
v = -v;
f = 1;
}
while(--i){
n = v % base;
n += '0';
if(n > '9'){
n += 'a' - ('9'+1);
if(op->ucase)
n += 'A'-'a';
}
b[i] = n;
v = (ulong)v / base;
if(i < 2)
break;
if(op->f2 >= 0 && i >= IDIGIT - op->f2)
continue;
if(v <= 0)
break;
}
if(f)
b[--i] = '-';
strconv(b+i, op, op->f1, -1);
}
static int
noconv(Op *op)
{
strconv("***ERROR: noconv***", op, 0, -1);
return 0;
}
static int
cconv(Op *op)
{
char b[2];
b[0] = va_arg(op->ap, char);
b[1] = 0;
strconv(b, op, op->f1, -1);
return 0;
}
static int
dconv(Op *op)
{
numconv(op, 10);
return 0;
}
static int
hconv(Op *op)
{
return -FSHORT;
}
static int
lconv(Op *op)
{
return -FLONG;
}
static int
uconv(Op *op)
{
return -FUNSIGN;
}
static int
sconv(Op *op)
{
char *p;
p = va_arg(op->ap, char*);
strconv(p?p:"<nil>", op, op->f1, op->f2);
return 0;
}
static int
xconv(Op *op)
{
numconv(op, 16);
return 0;
}
static int
Xconv(Op *op)
{
op->ucase = 1;
numconv(op, 16);
op->ucase = 0;
return 0;
}
static int
percent(Op *op)
{
put(op, '%');
return 0;
}
static void
put(Op *op, int c)
{
static int pos;
int opos;
if(c == 0)
return;
if(c == '\t'){
opos = pos;
pos = (opos+TABWIDTH) & (~(TABWIDTH-1));
while(opos++ < pos && op->p < op->ep)
*op->p++ = ' ';
return;
}
if(op->p < op->ep){
*op->p++ = c;
pos++;
}
if(c == '\n')
pos = 0;
}

View File

@ -1,3 +1,6 @@
#define MAX(x, y) ((x)>(y)?(x):(y))
#define MIN(x, y) ((x)<(y)?(x):(y))
// console.c
void cominit(ConDev *d);
void pcinit(ConDev *d);
@ -8,17 +11,44 @@ int comprobe(ConDev *d);
int comgetc(int dev);
void computc(int dev, int c);
// fmt.c
char* dofmt(Op *op, char *fmt);
int fmtinstall(int c, int (*f)(Op*));
char *doprint(char *p, char *ep, char *fmt, va_list ap);
int strlen(char *s);
// print.c
void putchar(int c);
void putstr(char *s, int l);
int getchar(void);
void print(const char *fmt, ...);
char* doprint(char *p, char *ep, char *fmt, va_list);
int print(char *fmt, ...);
int snprint(char *buf, int len, char *fmt, ...);
// a20.c
void a20up(void);
// long.c
// mem.c
void memprobe(void);
// cpu.c
void cpuidprobe(void);
// time.c
long getsecs(void);
// alloc.c
void *alloc(uint);
void free(void*);
// disk.c
int bdiskget(int dev, BIOSdisk *d);
int fmtdisk(Op *op);
void diskprobe(void);
// util
void* memset(void *dst, int v, int l);
static __inline int
major(int x)
{

View File

@ -2,6 +2,16 @@
#include "def.h"
#define AX 0
#define CX 4
#define DX 8
#define BX 12
#define BP 16
#define SI 20
#define DI 24
#define DS 28
#define ES 32
#define GEN_LABEL(n) X##n
// idt entry
@ -63,22 +73,12 @@
\
lidt Idtr;
.text
.globl BIOSreg
BIOSreg:
BIOS_AX: .long 0
BIOS_CX: .long 0
BIOS_DX: .long 0
BIOS_BX: .long 0
BIOS_BP: .long 0
BIOS_SI: .long 0
BIOS_DI: .long 0
BIOS_DS: .long 0
BIOS_ES: .long 0
.text
.code32
.globl pmode_init
.globl BIOSreg
BIOSreg:
.space 36, 0
// Table
// IDTR offset + 0 : entry 0
@ -246,11 +246,9 @@ EMUh: // build stack for real mode
movb %al, intno // save BIOS int vector
// BIOS_regs is area for saving the contents of registers returned by the BIOS during a BIOS CALL
movl BIOS_ES, %eax
movl $0x00, %eax
movl BIOSreg+ES, %eax
mov %eax, 7f
movl BIOS_DS, %eax
movl $0x00, %eax
movl BIOSreg+DS, %eax
mov %eax, 6f
prot2real
@ -300,12 +298,13 @@ intno = . -1;
// movl $Leax, %eax
.byte 0xb8
4: .long 0x90909090
mov %eax, BIOS_BX
movl %eax, BIOSreg+BX
// movl $Leax, %eax
.byte 0xb8
3: .long 0x90909090
mov %eax, BIOS_ES
movl %eax, BIOSreg+ES
// movl $Leax, %eax
.byte 0xb8
@ -318,13 +317,13 @@ intno = . -1;
movb %bh, 0xe*4(%esp) // restore eflags
// save register into BIOSREG
.code32
movl %eax, BIOS_AX
movl %ecx, BIOS_CX
movl %edx, BIOS_DX
movl %ebp, BIOS_BP
movl %esi, BIOS_SI
movl %edi, BIOS_DI
movl %eax, BIOSreg+AX
movl %ecx, BIOSreg+CX
movl %edx, BIOSreg+DX
movl %ebp, BIOSreg+BP
movl %esi, BIOSreg+SI
movl %edi, BIOSreg+DI
// clear NT(Nested Task Flag: 14) flag in eflag
// if 1 : interrupting

81
boot/mem.c Normal file
View File

@ -0,0 +1,81 @@
#include <u.h>
#include "dat.h"
#include "fn.h"
#define IOMEM_BEGIN 0x0A0000
#define IOMEM_END 0x100000
enum{
MAP_END = 0x00,
MAP_FREE = 0x01,
MAP_RES = 0x02,
MAP_ACPI_RECLAM = 0x03,
MAP_ACPI_NVS = 0x04,
};
static BIOSmmap*
int15_E820(BIOSmmap *m)
{
int rc, sig, off = 0;
do{
BIOSreg.es = ((uint)(m) >> 4);
__asm volatile("int $0x35; setc %b1"
: "=a" (sig), "=d" (rc), "=b" (off)
: "0" (0xE820), "1" (0x534d4150), "b" (off),
"c" (sizeof(*m)), "D" (((uint)m) & 0xf)
: "cc", "memory");
off = BIOSreg.bx;
if(rc &0xff || sig !=0x534d4150){
break;
if(m->type == 0)
m->type = MAP_RES;
}
m++;
}while(off);
return m;
}
static void
dumpmem(BIOSmmap *m)
{
ulong tot = 0;
for(BIOSmmap *p=m; p->type != MAP_END; ++p){
print("MEM % 2ud type %ud size % 10udKB at %08x:%08x\n",
p-m, p->type, (uint)(p->size/1024), (uint)(p->addr>>32), (uint)p->addr);
if(p->type == MAP_FREE)
tot += p->size/1024;
}
print("RAM low:%udKB high:%udKB\n", cnvmem, extmem);
print("Total free memory: %udKB\n", tot);
}
static int
isa20done(void)
{
register char *a = (char *)0x100000;
register char *b = (char *)0x000000;
return *a != *b;
}
void
memprobe(void)
{
BIOSmmap *m;
cnvmem = extmem = 0;
m = int15_E820(biosmmap);
m->type = MAP_END;
for(m = biosmmap; m->type != MAP_END; ++m){
if(m->type != MAP_FREE || m->size <= 0)
continue;
if(m->addr < IOMEM_BEGIN)
cnvmem = MAX(cnvmem, m->addr + m->size)/1024;
if(m->addr >= IOMEM_END)
extmem += m->size/1024;
}
dumpmem(biosmmap);
print("A20:%s\n", isa20done() ? "ok" : "no");
}

View File

@ -2,61 +2,49 @@
#include "dat.h"
#include "fn.h"
#define TABWIDTH 4
#define BUFSIZE 1024
static void conputc(int c);
static void conputc(int);
static int congetc(void);
static void doprint(void (*put)(int), const char *fmt, va_list ap);
static void putint(void (*put)(int), int n, const char *sym, int base);
static int pos = 0;
void
print(const char *fmt, ...)
char*
doprint(char *p, char *ep, char *fmt, va_list ap)
{
Op op = { .p = p, .ep = ep, .ap = ap };
return dofmt(&op, fmt);
}
int
print(char *fmt, ...)
{
char buf[BUFSIZE], *p;
va_list args;
va_start(args, fmt);
doprint(putchar, fmt, args);
p = doprint(buf, buf+sizeof(buf), fmt, args);
va_end(args);
putstr(buf, p-buf);
return p-buf;
}
static void
doprint(void (*put)(int), const char *s, va_list ap)
int
snprint(char *buf, int len, char *fmt, ...)
{
while(*s){
if(*s != '%'){
put(*s++);
continue;
}
++s;
switch(*s){
case 'd':
putint(put, va_arg(ap,int), "0123456789", 10);
break;
case 'x':
putint(put, va_arg(ap,int), "0123456789abcdef", 16);
break;
case 'X':
putint(put, va_arg(ap,int), "0123456789ABCDEF", 16);
break;
case 's':
for(char *p=va_arg(ap,char*); *p; ++p)
put(*p);
break;
default:
return;
}
++s;
}
}
char *p;
va_list args;
va_start(args, fmt);
p = doprint(buf, buf+len, fmt, args);
va_end(args);
return p-buf;
}
int
getchar(void)
{
int c;
c = congetc();
c = congetc();
if(c == '\r')
c = '\n';
if((c < ' ' && c != '\n') || c == '\177')
@ -65,6 +53,13 @@ getchar(void)
return c;
}
void
putstr(char *s, int l)
{
while(l--)
putchar(*s++);
}
void
putchar(int c)
{
@ -72,24 +67,20 @@ putchar(int c)
case '\177':
conputc('\b');
conputc(' ');
break;
case '\b':
conputc('\b');
if(pos > 0)
--pos;
break;
case '\t':
do{
for(int i = 0; i < TABWIDTH; ++i)
conputc(' ');
}while(++pos % TABWIDTH);
break;
case '\n':
case '\r':
conputc(c);
pos = 0;
break;
default:
conputc(c);
++pos;
break;
}
}
@ -109,19 +100,3 @@ congetc(void)
{
return con->getc(con->dev);
}
static void
putint(void (*put)(int), int n, const char *sym, int base)
{
int i;
char buf[16];
i = 0;
do{
buf[i++] = n%base;
n /= base;
}while(n);
do{
put((int)sym[(int)buf[--i]]);
}while(i);
}