Skip to content

Commit 0637256

Browse files
committed
User mode printf.
1 parent 2f72d43 commit 0637256

File tree

9 files changed

+389
-4
lines changed

9 files changed

+389
-4
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ stdio.o \
3737
stdlib.o \
3838
string.o
3939

40+
STDLIB = stdlib/assembly_functions.o \
41+
stdlib/stdio.o
42+
4043
all: os.iso
4144

4245
%.o: %.c
@@ -56,7 +59,7 @@ start_user_program.o: start_user_program.s
5659
user_program.o: user_program.c
5760
$(GCC) $(CFLAGS) $< -o $@
5861

59-
user_program.bin: user_program.o start_user_program.o stdlib/assembly_functions.o
62+
user_program.bin: user_program.o start_user_program.o $(STDLIB)
6063
$(LD) -T link_user_program.ld -melf_i386 $^ -o $@
6164

6265
os.iso: kernel.elf user_program.bin menu.lst

interrupts.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ void interrupt_handler(struct cpu_state cpu, uint32_t interrupt_number, uint32_t
9393
if (error_code & 0b10000) {
9494
fprintf(LOG, "- caused by an instruction fetch.\n");
9595
}
96+
while(1){}
9697
break;
9798

9899
case(INT_SOFTWARE):

script/user_program_dump

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env ruby
2+
raw = `xxd user_program.bin`
3+
4+
lines = raw.split("\n")
5+
6+
formatted_lines = lines.map do |line|
7+
line[9,41].tr(' ', '')
8+
end
9+
10+
puts formatted_lines.join("").gsub(/(.{2})/, '\1 ')

stdio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void write_uint(write_byte_t write_byte, uint32_t value) {
9595
}
9696

9797
bool past_leading_zeroes = false;
98-
for (int place = 10; place >= 0; place--) {
98+
for (int place = 9; place >= 0; place--) {
9999
if (output[place] > 0) {
100100
past_leading_zeroes = true;
101101
}

stdlib/stdarg.h

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
2+
3+
This file is part of GCC.
4+
5+
GCC is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 2, or (at your option)
8+
any later version.
9+
10+
GCC is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with GCC; see the file COPYING. If not, write to
17+
the Free Software Foundation, 59 Temple Place - Suite 330,
18+
Boston, MA 02111-1307, USA. */
19+
20+
/* As a special exception, if you include this header file into source
21+
files compiled by GCC, this header file does not by itself cause
22+
the resulting executable to be covered by the GNU General Public
23+
License. This exception does not however invalidate any other
24+
reasons why the executable file might be covered by the GNU General
25+
Public License. */
26+
27+
/*
28+
* ISO C Standard: 7.15 Variable arguments <stdarg.h>
29+
*/
30+
31+
#ifndef _STDARG_H
32+
#ifndef _ANSI_STDARG_H_
33+
#ifndef __need___va_list
34+
#define _STDARG_H
35+
#define _ANSI_STDARG_H_
36+
#endif /* not __need___va_list */
37+
#undef __need___va_list
38+
39+
/* Define __gnuc_va_list. */
40+
41+
#ifndef __GNUC_VA_LIST
42+
#define __GNUC_VA_LIST
43+
typedef __builtin_va_list __gnuc_va_list;
44+
#endif
45+
46+
/* Define the standard macros for the user,
47+
if this invocation was from the user program. */
48+
#ifdef _STDARG_H
49+
50+
#define va_start(v,l) __builtin_va_start(v,l)
51+
#define va_end(v) __builtin_va_end(v)
52+
#define va_arg(v,l) __builtin_va_arg(v,l)
53+
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
54+
#define va_copy(d,s) __builtin_va_copy(d,s)
55+
#endif
56+
#define __va_copy(d,s) __builtin_va_copy(d,s)
57+
58+
/* Define va_list, if desired, from __gnuc_va_list. */
59+
/* We deliberately do not define va_list when called from
60+
stdio.h, because ANSI C says that stdio.h is not supposed to define
61+
va_list. stdio.h needs to have access to that data type,
62+
but must not use that name. It should use the name __gnuc_va_list,
63+
which is safe because it is reserved for the implementation. */
64+
65+
#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */
66+
#undef _VA_LIST
67+
#endif
68+
69+
#ifdef _BSD_VA_LIST
70+
#undef _BSD_VA_LIST
71+
#endif
72+
73+
#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
74+
/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
75+
so we must avoid testing it and setting it here.
76+
SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
77+
have no conflict with that. */
78+
#ifndef _VA_LIST_
79+
#define _VA_LIST_
80+
#ifdef __i860__
81+
#ifndef _VA_LIST
82+
#define _VA_LIST va_list
83+
#endif
84+
#endif /* __i860__ */
85+
typedef __gnuc_va_list va_list;
86+
#ifdef _SCO_DS
87+
#define __VA_LIST
88+
#endif
89+
#endif /* _VA_LIST_ */
90+
#else /* not __svr4__ || _SCO_DS */
91+
92+
/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
93+
But on BSD NET2 we must not test or define or undef it.
94+
(Note that the comments in NET 2's ansi.h
95+
are incorrect for _VA_LIST_--see stdio.h!) */
96+
#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
97+
/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */
98+
#ifndef _VA_LIST_DEFINED
99+
/* The macro _VA_LIST is used in SCO Unix 3.2. */
100+
#ifndef _VA_LIST
101+
/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
102+
#ifndef _VA_LIST_T_H
103+
/* The macro __va_list__ is used by BeOS. */
104+
#ifndef __va_list__
105+
typedef __gnuc_va_list va_list;
106+
#endif /* not __va_list__ */
107+
#endif /* not _VA_LIST_T_H */
108+
#endif /* not _VA_LIST */
109+
#endif /* not _VA_LIST_DEFINED */
110+
#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
111+
#define _VA_LIST_
112+
#endif
113+
#ifndef _VA_LIST
114+
#define _VA_LIST
115+
#endif
116+
#ifndef _VA_LIST_DEFINED
117+
#define _VA_LIST_DEFINED
118+
#endif
119+
#ifndef _VA_LIST_T_H
120+
#define _VA_LIST_T_H
121+
#endif
122+
#ifndef __va_list__
123+
#define __va_list__
124+
#endif
125+
126+
#endif /* not _VA_LIST_, except on certain systems */
127+
128+
#endif /* not __svr4__ */
129+
130+
#endif /* _STDARG_H */
131+
132+
#endif /* not _ANSI_STDARG_H_ */
133+
#endif /* not _STDARG_H */

stdlib/stdio.c

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#include "stdio.h"
2+
3+
#include "assembly_functions.h"
4+
#include "stdarg.h"
5+
6+
#define BUFFER_SIZE 128
7+
8+
struct buffer_t {
9+
char bytes[BUFFER_SIZE+1]; // 1 bytes for null character
10+
uint8_t bytes_in_buffer;
11+
};
12+
13+
void flush_buffer(struct buffer_t* buffer) {
14+
write_to_screen(buffer->bytes);
15+
buffer->bytes_in_buffer = 0;
16+
}
17+
18+
void write_byte(char byte, struct buffer_t* buffer) {
19+
buffer->bytes[buffer->bytes_in_buffer] = byte;
20+
21+
buffer->bytes_in_buffer++;
22+
23+
if (buffer->bytes_in_buffer >= BUFFER_SIZE) {
24+
flush_buffer(buffer);
25+
}
26+
}
27+
28+
void write_half_byte(uint8_t half_byte, bool upcase, struct buffer_t* buffer) {
29+
switch (half_byte) {
30+
case 0x0:
31+
write_byte('0', buffer);
32+
break;
33+
case 0x1:
34+
write_byte('1', buffer);
35+
break;
36+
case 0x2:
37+
write_byte('2', buffer);
38+
break;
39+
case 0x3:
40+
write_byte('3', buffer);
41+
break;
42+
case 0x4:
43+
write_byte('4', buffer);
44+
break;
45+
case 0x5:
46+
write_byte('5', buffer);
47+
break;
48+
case 0x6:
49+
write_byte('6', buffer);
50+
break;
51+
case 0x7:
52+
write_byte('7', buffer);
53+
break;
54+
case 0x8:
55+
write_byte('8', buffer);
56+
break;
57+
case 0x9:
58+
write_byte('9', buffer);
59+
break;
60+
case 0xA:
61+
write_byte(upcase ? 'A' : 'a', buffer);
62+
break;
63+
case 0xB:
64+
write_byte(upcase ? 'B' : 'b', buffer);
65+
break;
66+
case 0xC:
67+
write_byte(upcase ? 'C' : 'c', buffer);
68+
break;
69+
case 0xD:
70+
write_byte(upcase ? 'D' : 'd', buffer);
71+
break;
72+
case 0xE:
73+
write_byte(upcase ? 'E' : 'e', buffer);
74+
break;
75+
case 0xF:
76+
write_byte(upcase ? 'F' : 'f', buffer);
77+
break;
78+
}
79+
}
80+
81+
void print_uint8(uint8_t data, struct buffer_t* buffer) {
82+
uint8_t half_byte;
83+
write_byte('0', buffer);
84+
write_byte('x', buffer);
85+
for (int i = 1; i >=0; i--) {
86+
half_byte = (data >> (4*i)) & 0x0F;
87+
write_half_byte(half_byte, true, buffer);
88+
}
89+
}
90+
91+
void write_string(char* s, struct buffer_t* buffer) {
92+
while(*s) {
93+
write_byte(*s, buffer);
94+
s++;
95+
}
96+
}
97+
98+
void write_uint(uint32_t value, struct buffer_t* buffer) {
99+
char output[10];
100+
for (int place = 0; place < 10; place++) {
101+
output[place] = value % 10;
102+
value = value / 10;
103+
}
104+
105+
bool past_leading_zeroes = false;
106+
for (int place = 9; place >= 0; place--) {
107+
if (output[place] > 0) {
108+
past_leading_zeroes = true;
109+
}
110+
111+
if (past_leading_zeroes) {
112+
write_byte(output[place] + '0', buffer);
113+
}
114+
}
115+
}
116+
117+
void write_int(int value, struct buffer_t* buffer) {
118+
if (value < 0) {
119+
write_byte('-', buffer);
120+
value *= -1;
121+
}
122+
write_uint(value, buffer);
123+
}
124+
125+
void write_octal(uint32_t value, struct buffer_t* buffer) {
126+
write_byte('0', buffer);
127+
write_byte('o', buffer);
128+
bool past_leading_zeroes = false;
129+
uint8_t part = (value >> 30) & 0b11;
130+
if (part > 0) {
131+
write_half_byte(part, true, buffer);
132+
past_leading_zeroes = true;
133+
}
134+
for (int i = 10; i >=0; i--) {
135+
part = (value >> (3*i)) & 0b111;
136+
if (part > 0) {
137+
past_leading_zeroes = true;
138+
}
139+
140+
if (past_leading_zeroes) {
141+
write_half_byte(part, true, buffer);
142+
}
143+
}
144+
}
145+
146+
enum format_string_mode {NORMAL, COMMAND};
147+
int printf (const char * format, ...) {
148+
va_list vl;
149+
va_start(vl,format);
150+
151+
struct buffer_t buffer;
152+
for (int i = 0; i <=BUFFER_SIZE; i++) {
153+
buffer.bytes[i] = 0;
154+
buffer.bytes_in_buffer = 0;
155+
}
156+
157+
int i = 0;
158+
enum format_string_mode mode = NORMAL;
159+
uint32_t vararg;
160+
while (format[i]) {
161+
switch (mode) {
162+
case (NORMAL):
163+
if (format[i] == '%') {
164+
mode = COMMAND;
165+
} else {
166+
write_byte(format[i], &buffer);
167+
}
168+
break;
169+
case (COMMAND):
170+
if (format[i] == '%') {
171+
write_byte('%', &buffer);
172+
} else if (format[i] == 'c') {
173+
write_byte((uint32_t) va_arg(vl,uint32_t), &buffer);
174+
} else if (format[i] == 'i' || format[i] == 'd') {
175+
write_int(va_arg(vl, int), &buffer);
176+
} else if (format[i] == 'o') {
177+
write_octal(va_arg(vl, int), &buffer);
178+
} else if (format[i] == 's') {
179+
write_string((char*) va_arg(vl,char*), &buffer);
180+
} else if (format[i] == 'u') {
181+
write_uint(va_arg(vl, uint32_t), &buffer);
182+
} else if (format[i] == 'x') {
183+
write_byte('0', &buffer);
184+
write_byte('x', &buffer);
185+
vararg = va_arg(vl,uint32_t);
186+
for (int i = 7; i >=0; i--) {
187+
write_half_byte((vararg >> (4*i)) & 0x0F, false, &buffer);
188+
}
189+
} else if (format[i] == 'X') {
190+
write_byte('0', &buffer);
191+
write_byte('x', &buffer);
192+
vararg = va_arg(vl,uint32_t);
193+
for (int i = 7; i >=0; i--) {
194+
write_half_byte((vararg >> (4*i)) & 0x0F, true, &buffer);
195+
}
196+
} else {
197+
write_byte('?', &buffer);
198+
mode = NORMAL;
199+
}
200+
mode = NORMAL;
201+
break;
202+
}
203+
i++;
204+
}
205+
flush_buffer(&buffer);
206+
return i;
207+
}

0 commit comments

Comments
 (0)