Browse Source

initcalls: Add initial implementation

Create simple serial subsystem which makes use of initcalls, and convert
existing serial drivers to its use.
Aaron Lindsay 7 years ago
parent
commit
9d86813d8c
14 changed files with 219 additions and 102 deletions
  1. 4 1
      drivers/kernel.mk
  2. 18 2
      drivers/pi_mini_uart.c
  3. 15 1
      drivers/pl011.c
  4. 40 0
      drivers/serial.c
  5. 1 1
      include/console.h
  6. 27 0
      include/drivers/serial.h
  7. 34 0
      include/init.h
  8. 2 2
      include/print.h
  9. 5 3
      kernel/console.c
  10. 37 0
      kernel/init.c
  11. 1 0
      kernel/kernel.mk
  12. 10 9
      kernel/print.c
  13. 11 78
      kernel/start_kernel.c
  14. 14 5
      link.ld

+ 4 - 1
drivers/kernel.mk

@@ -3,6 +3,9 @@ SUBDIRS :=
3 3
 
4 4
 include $(BASEDIR)/header.mk
5 5
 
6
+OBJS_$(d) := \
7
+	$(d)/serial.o
8
+
6 9
 OBJS_$(d)_$(CONFIG_VEXPRESS_A9) := \
7 10
 	$(d)/pl011.o \
8 11
 	$(d)/pl111.o
@@ -15,6 +18,6 @@ OBJS_$(d)_$(CONFIG_RPI) := \
15 18
 	$(d)/bcm2835_mailbox.o \
16 19
 	$(d)/bcm2835_videocore.o
17 20
 
18
-KOBJS += $(OBJS_$(d)_y)
21
+KOBJS += $(OBJS_$(d)) $(OBJS_$(d)_y)
19 22
 
20 23
 include $(BASEDIR)/footer.mk

+ 18 - 2
drivers/pi_mini_uart.c

@@ -18,8 +18,11 @@
18 18
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 19
  */
20 20
 
21
+#include <init.h>
21 22
 #include <types.h>
22 23
 
24
+#include <drivers/serial.h>
25
+
23 26
 #define VC_MMU_IO_OFFSET(addr) (addr - 0x7E000000 + 0x20000000)
24 27
 
25 28
 /* Auxiliary IO registers (includes both mini-UART and SPI) */
@@ -57,7 +60,7 @@
57 60
 #define GPPUD VC_MMU_IO_OFFSET(0x7E200094)
58 61
 #define GPPUDCLK0 VC_MMU_IO_OFFSET(0x7E200098)
59 62
 
60
-void mini_uart_init() {
63
+void mini_uart_device_init() {
61 64
 	uint32 aux_enables;
62 65
 	uint32 gpfsel1;
63 66
 	unsigned int i;
@@ -96,10 +99,23 @@ void mini_uart_init() {
96 99
 	*(uint32 *)AUX_MU_CNTL_REG = 2; //enable TX
97 100
 }
98 101
 
99
-void mini_uart_putc(char c) {
102
+int mini_uart_putc(char c) {
100 103
 	/* Wait until the serial buffer is empty */
101 104
 	while (!(*(volatile uint32*)AUX_MU_LSR_REG & MINI_UART_TX_EMPTY));
102 105
 
103 106
 	/* When it's empty, write our character */
104 107
 	*(volatile uint32*)AUX_MU_IO_REG = c;
108
+
109
+	return 0;
110
+}
111
+
112
+struct serial_dev mini_uart_dev = {
113
+	.putc = &mini_uart_putc
114
+};
115
+
116
+void mini_uart_init() {
117
+	mini_uart_device_init();
118
+	serial_register_device(&mini_uart_dev);
105 119
 }
120
+
121
+early_initcall(mini_uart_init);

+ 15 - 1
drivers/pl011.c

@@ -18,17 +18,31 @@
18 18
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 19
  */
20 20
 
21
+#include <init.h>
22
+#include <drivers/serial.h>
21 23
 #include <types.h>
22 24
 
23 25
 #define PL011_SERIAL_BASE 0x10009000
24 26
 #define PL011_SERIAL_FLAG_REGISTER 0x18
25 27
 #define PL011_SERIAL_BUFFER_FULL (1 << 5)
26 28
 
27
-void pl011_putc(char c)
29
+int pl011_putc(char c)
28 30
 {
29 31
 	/* Wait until the serial buffer is empty */
30 32
 	while (*(volatile uint32*)(PL011_SERIAL_BASE + PL011_SERIAL_FLAG_REGISTER) & (PL011_SERIAL_BUFFER_FULL));
31 33
 
32 34
 	/* When it's empty, put our character at the base */
33 35
 	*(volatile uint32*)PL011_SERIAL_BASE = c;
36
+
37
+	return 0;
34 38
 }
39
+
40
+struct serial_dev pl011_dev = {
41
+	.putc = &pl011_putc
42
+};
43
+
44
+void pl011_init() {
45
+	serial_register_device(&pl011_dev);
46
+}
47
+
48
+early_initcall(pl011_init);

+ 40 - 0
drivers/serial.c

@@ -0,0 +1,40 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+#include <init.h>
22
+#include <drivers/serial.h>
23
+
24
+struct serial_dev *first_serial_dev;
25
+
26
+int serial_register_device(struct serial_dev *sdev) {
27
+	if (!first_serial_dev)
28
+		first_serial_dev = sdev;
29
+	return 0;
30
+}
31
+
32
+struct serial_dev *serial_first_device() {
33
+	return first_serial_dev;
34
+}
35
+
36
+void serial_init() {
37
+	first_serial_dev = 0;
38
+}
39
+
40
+driversubsys_initcall(serial_init);

+ 1 - 1
include/console.h

@@ -22,6 +22,6 @@
22 22
 #define CONSOLE_H
23 23
 
24 24
 void console_init(struct fb *f);
25
-void console_putc(char c);
25
+int console_putc(char c);
26 26
 
27 27
 #endif /* CONSOLE_H */

+ 27 - 0
include/drivers/serial.h

@@ -0,0 +1,27 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+struct serial_dev {
22
+	//TODO add more functions and attributes here
23
+	int (*putc)(char);
24
+};
25
+
26
+int serial_register_device(struct serial_dev *sdev);
27
+struct serial_dev *serial_first_device();

+ 34 - 0
include/init.h

@@ -0,0 +1,34 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+void init_earlyinitcalls();
22
+void init_initcalls();
23
+
24
+struct initcall_func {
25
+	void (*fptr)();
26
+};
27
+
28
+#define _initcall(level_name, level, func) struct initcall_func func##_##level##_initcall \
29
+	__attribute__ ((section ("." level_name "initcalls"))) = { func }
30
+
31
+/* The actual calls to be used externally */
32
+#define early_initcall(func) _initcall("early", 0, func)
33
+#define driversubsys_initcall(func) _initcall("driversubsys", 1, func)
34
+#define device_initcall(func) _initcall("device", 2, func)

+ 2 - 2
include/print.h

@@ -21,8 +21,8 @@
21 21
 #ifndef PRINT_H
22 22
 #define PRINT_H
23 23
 
24
-void print_init(void (*putc)(char));
24
+void print_init(int (*putc)(char));
25 25
 int print(char *fmt, ...);
26
-int print_func(void (putcf)(char), char *fmt, ...);
26
+int print_func(int (putcf)(char), char *fmt, ...);
27 27
 
28 28
 #endif /* PRINT_H */

+ 5 - 3
kernel/console.c

@@ -123,17 +123,17 @@ void console_newline() {
123 123
 	}
124 124
 }
125 125
 
126
-void console_putc(char c) {
126
+int console_putc(char c) {
127 127
 	char *console_buffer_end = console_buffer + chars_per_line * lines;
128 128
 	char *write_char_at;
129 129
 
130 130
 	switch (c) {
131 131
 		case '\n':
132 132
 			console_newline();
133
-			return;
133
+			return 0;
134 134
 		case '\r':
135 135
 			curr_char = 0;
136
-			return;
136
+			return 0;
137 137
 		default:
138 138
 			break;
139 139
 	}
@@ -148,4 +148,6 @@ void console_putc(char c) {
148 148
 	*write_char_at = c;
149 149
 
150 150
 	console_char_to_fb(c, curr_char++, curr_line);
151
+
152
+	return 0;
151 153
 }

+ 37 - 0
kernel/init.c

@@ -0,0 +1,37 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+#include <types.h>
22
+#include <print.h>
23
+
24
+extern uint32 early_initcalls_start, early_initcalls_end;
25
+extern uint32 initcalls_start, initcalls_end;
26
+
27
+void init_earlyinitcalls() {
28
+	void (**initcall)();
29
+	for (initcall = (void (**)()) &early_initcalls_start; initcall < (void (**)())&early_initcalls_end; initcall++)
30
+		(*initcall)();
31
+}
32
+
33
+void init_initcalls() {
34
+	void (**initcall)();
35
+	for (initcall = (void (**)()) &initcalls_start; initcall < (void (**)())&initcalls_end; initcall++)
36
+		(*initcall)();
37
+}

+ 1 - 0
kernel/kernel.mk

@@ -7,6 +7,7 @@ OBJS_$(d) := $(d)/atags.o \
7 7
 	$(d)/console.o \
8 8
 	$(d)/font.o \
9 9
 	$(d)/framebuffer.o \
10
+	$(d)/init.o \
10 11
 	$(d)/kmalloc.o \
11 12
 	$(d)/list.o \
12 13
 	$(d)/math.o \

+ 10 - 9
kernel/print.c

@@ -23,22 +23,23 @@
23 23
 
24 24
 /* This function exists solely so crashes don't happen if putc() gets
25 25
  * called before it is initialized. */
26
-void putc_initial(char c) {
26
+int putc_initial(char c) {
27 27
 	(void)c;
28
+	return 0;
28 29
 }
29
-void (*print_putc)(char) = &putc_initial;
30
+int (*print_putc)(char) = &putc_initial;
30 31
 
31
-void print_init(void (*putcfn)(char)) {
32
+void print_init(int (*putcfn)(char)) {
32 33
 	if (putcfn)
33 34
 		print_putc = putcfn;
34 35
 }
35 36
  
36
-void puts(void (*putc)(char), const char *s)
37
+void puts(int (*putc)(char), const char *s)
37 38
 {
38 39
     while (*s) putc (*s++);
39 40
 }
40 41
 
41
-void puti(void (*putc)(char), int i)
42
+void puti(int (*putc)(char), int i)
42 43
 {
43 44
 	unsigned int left;
44 45
 	char buf[1 << (sizeof(int)*8) / 10];
@@ -64,7 +65,7 @@ void puti(void (*putc)(char), int i)
64 65
 		putc(*p);
65 66
 }
66 67
 
67
-void putx(void (*putc)(char), unsigned int i) {
68
+void putx(int (*putc)(char), unsigned int i) {
68 69
 	int j;
69 70
 
70 71
 	puts(putc, "0x");
@@ -78,7 +79,7 @@ void putx(void (*putc)(char), unsigned int i) {
78 79
 	}
79 80
 }
80 81
 
81
-void putb(void (*putc)(char), unsigned int i) {
82
+void putb(int (*putc)(char), unsigned int i) {
82 83
 	int j;
83 84
 
84 85
 	puts(putc, "0b");
@@ -88,7 +89,7 @@ void putb(void (*putc)(char), unsigned int i) {
88 89
 	}
89 90
 }
90 91
 
91
-int _print(void (*putc)(char), char *fmt, va_list arg) {
92
+int _print(int (*putc)(char), char *fmt, va_list arg) {
92 93
 	char *c;
93 94
 	for (c = fmt; *c; c++) {
94 95
 		if (*c == '%') {
@@ -138,7 +139,7 @@ int print(char *fmt, ...) {
138 139
 }
139 140
 
140 141
 
141
-int print_func(void (*putc)(char), char *fmt, ...) {
142
+int print_func(int (*putc)(char), char *fmt, ...) {
142 143
 	int ret;
143 144
 	va_list arg;
144 145
 

+ 11 - 78
kernel/start_kernel.c

@@ -19,6 +19,7 @@
19 19
  */
20 20
 
21 21
 #include <atags.h>
22
+#include <init.h>
22 23
 #include <kmalloc.h>
23 24
 #include <mmu.h>
24 25
 #include <mm.h>
@@ -26,13 +27,13 @@
26 27
 #include <framebuffer.h>
27 28
 #include <console.h>
28 29
 
30
+#include <drivers/serial.h>
31
+
29 32
 #ifdef CONFIG_VEXPRESS_A9
30
-#include <drivers/pl011.h>
31 33
 #include <drivers/pl111.h>
32 34
 #endif
33 35
 
34 36
 #ifdef CONFIG_RPI
35
-#include <drivers/pi_mini_uart.h>
36 37
 #include <drivers/bcm2835_videocore.h>
37 38
 #endif
38 39
 
@@ -56,74 +57,11 @@ void video_init(void) {
56 57
 #endif
57 58
 }
58 59
 
59
-void test_mm() {
60
-	struct page *p, *q;
61
-
62
-	print("\ntest_mm():\n");
63
-
64
-	p = mm_get_free_pages(0);
65
-	if (p)
66
-		print("%x, %x\n", p, p->address);
67
-	else
68
-		print("Error: failed to allocate memory for p\n");
69
-
70
-	q = mm_get_free_pages(4);
71
-	if (q)
72
-		print("%x, %x\n", q, q->address);
73
-	else
74
-		print("Error: failed to allocate memory for q\n");
75
-
76
-	mm_put_free_pages(p);
77
-	mm_put_free_pages(q);
78
-
79
-	q = mm_get_free_pages(1);
80
-	if (q)
81
-		print("%x, %x\n", q, q->address);
82
-	else
83
-		print("Error: failed to allocate memory for q\n");
84
-
85
-	p = mm_get_free_pages(0);
86
-	if (p)
87
-		print("%x, %x\n", p, p->address);
88
-	else
89
-		print("Error: failed to allocate memory for p\n");
90
-	mm_put_free_pages(p);
91
-	mm_put_free_pages(q);
92
-
93
-}
94
-
95
-void test_kmalloc() {
96
-	void *a, *b, *c, *d;
97
-
98
-	print("\ntest_kmalloc():\n");
99
-
100
-	a = kmalloc(4);
101
-	print("a: %x\n", a);
102
-	b = kmalloc(13);
103
-	print("b: %x\n", b);
104
-	c = kmalloc(4);
105
-	print("c: %x\n", c);
106
-	d = kmalloc(25);
107
-	print("d: %x\n", d);
108
-
109
-	kfree(c);
110
-	kfree(b);
111
-	kfree(a);
112
-	kfree(d);
113
-
114
-	a = kmalloc(13);
115
-	print("a: %x\n", a);
116
-	b = kmalloc(4);
117
-	print("b: %x\n", b);
118
-	c = kmalloc(25);
119
-	print("c: %x\n", c);
120
-	d = kmalloc(7);
121
-	print("d: %x\n", d);
122
-}
60
+void serial_console_init() {
61
+	struct serial_dev *sdev = serial_first_device();
123 62
 
124
-void test_memory() {
125
-	test_mm();
126
-	test_kmalloc();
63
+	if (sdev)
64
+		print_init(sdev->putc);
127 65
 }
128 66
 
129 67
 void kmalloc_init();
@@ -135,14 +73,9 @@ int main(void) {
135 73
 	//setup MMU
136 74
 	mmu_reinit();
137 75
 
138
-	//initialize the serial console
139
-#ifdef CONFIG_VEXPRESS_A9
140
-	print_init(&pl011_putc);
141
-#endif
142
-#ifdef CONFIG_RPI
143
-	mini_uart_init();
144
-	print_init(&mini_uart_putc);
145
-#endif
76
+	init_earlyinitcalls();
77
+
78
+	serial_console_init();
146 79
 
147 80
 	//setup memory
148 81
 	mm_init();
@@ -159,7 +92,7 @@ int main(void) {
159 92
 		declare_memory_region(lower, upper);
160 93
 	} while (!atags_next_mem_region(&atags));
161 94
 
162
-	test_memory();
95
+	init_initcalls();
163 96
 
164 97
 	video_init();
165 98
 	console_init(&myfb);

+ 14 - 5
link.ld

@@ -2,9 +2,18 @@ ENTRY (start)
2 2
 
3 3
 SECTIONS
4 4
 {
5
-    . = 0x80100000;
6
-    .text : { *(.text*) *(.rodata*) }
7
-    .data : { *(.data*) }
8
-    .bss : { *(.bss*) *(COMMON*) }
9
-    kernel_end = .;
5
+	. = 0x80100000;
6
+	.text : { *(.text*) *(.rodata*) }
7
+	.init : {
8
+		early_initcalls_start = .;
9
+		*(.earlyinitcalls*)
10
+		early_initcalls_end = .;
11
+		initcalls_start = .;
12
+		*(.driversubsysinitcalls*)
13
+		*(.deviceinitcalls*)
14
+		initcalls_end = .;
15
+	}
16
+	.data : { *(.data*) }
17
+	.bss : { *(.bss*) *(COMMON*) }
18
+	kernel_end = .;
10 19
 }