xref: /openbmc/skeleton/op-hostctl/control_host_obj.c (revision 783fbb010819ad497352250d3472ff04438bd3c6)
1  #include <stdio.h>
2  #include <stdlib.h>
3  #include <string.h>
4  #include <fcntl.h>
5  #include <unistd.h>
6  #include <sys/stat.h>
7  #include <sys/mman.h>
8  #include <errno.h>
9  
10  #include <openbmc_intf.h>
11  #include <openbmc.h>
12  
13  /* ------------------------------------------------------------------------- */
14  static const gchar* dbus_object_path = "/org/openbmc/control";
15  static const gchar* instance_name = "host0";
16  static const gchar* dbus_name = "org.openbmc.control.Host";
17  
18  static GDBusObjectManagerServer *manager = NULL;
19  
20  #define PPC_BIT32(bit)          (0x80000000UL >> (bit))
21  
22  #define FSI_EXTERNAL_MODE_PATH	"/sys/devices/platform/gpio-fsi/external_mode"
23  #define FSI_SCAN_PATH		"/sys/class/fsi-master/fsi0/rescan"
24  
25  /* TODO: Change this over to the cfam path once the cfam chardev patches have landed */
26  #define FSI_RAW_PATH		"/sys/class/fsi-master/fsi0/slave@00:00/raw"
27  
28  #define FSI_SCAN_DELAY_US	10000
29  
30  /* Attention registers */
31  #define FSI_A_SI1S		0x081c
32  #define TRUE_MASK		0x100d
33  #define INTERRUPT_STATUS_REG	0x100b
34  
35  /* SBE boot register and values */
36  #define SBE_VITAL		0x281c
37  #define SBE_WARMSTART		PPC_BIT32(0)
38  #define SBE_HW_TRIGGER		PPC_BIT32(2)
39  #define SBE_UPDATE_1ST_NIBBLE	PPC_BIT32(3)
40  #define SBE_IMAGE_SELECT	PPC_BIT32(8)
41  #define SBE_UPDATE_3RD_NIBBLE	PPC_BIT32(11)
42  
43  /* Once the side is selected and attention bits are set, this starts the SBE */
44  #define START_SBE		(SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE)
45  
46  /* Primary is first side. Golden is second side */
47  #define PRIMARY_SIDE		(SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE)
48  #define GOLDEN_SIDE		(SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \
49  				 SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE)
50  
51  static gboolean
on_init(Control * control,GDBusMethodInvocation * invocation,gpointer user_data)52  on_init(Control *control,
53  		GDBusMethodInvocation *invocation,
54  		gpointer user_data)
55  {
56  	(void) user_data;
57  	control_complete_init(control,invocation);
58  	return TRUE;
59  }
60  
61  static gint
fsi_putcfam(int fd,uint64_t addr64,uint32_t val_host)62  fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host)
63  {
64  	int rc;
65  	uint32_t val = htobe32(val_host);
66  	/* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */
67  	uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2);
68  
69  	rc = lseek(fd, addr, SEEK_SET);
70  	if (rc < 0) {
71  		g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr,
72  				strerror(errno));
73  		return errno;
74  	};
75  
76  	rc = write(fd, &val, sizeof(val));
77  	if (rc < 0) {
78  		g_print("ERROR HostControl: cfam write failed: %s\n",
79  				strerror(errno));
80  		return errno;
81  	}
82  
83  	return 0;
84  }
85  
fsi_rescan(void)86  static int fsi_rescan(void)
87  {
88  	char *one = "1";
89  	int fd, rc;
90  
91  	fd = open(FSI_SCAN_PATH, O_WRONLY);
92  	if (fd < 0) {
93  		g_print("ERROR HostControl: Failed to open path '%s': %s\n",
94  				FSI_SCAN_PATH, strerror(errno));
95  		return errno;
96  	}
97  	rc = write(fd, one, sizeof(*one));
98  	close(fd);
99  	if (rc < 0) {
100  		g_print("ERROR HostControl: Failed to perform FSI scan: %s\n",
101  				strerror(errno));
102  		return errno;
103  	}
104  	g_print("HostControl: Performing FSI scan (delay %d us)\n",
105  			FSI_SCAN_DELAY_US);
106  	usleep(FSI_SCAN_DELAY_US);
107  
108  	return 0;
109  }
110  
111  static gboolean
on_boot(ControlHost * host,GDBusMethodInvocation * invocation,gpointer user_data)112  on_boot(ControlHost *host,
113  		GDBusMethodInvocation *invocation,
114  		gpointer user_data)
115  {
116  	(void) user_data;
117  	int rc, cfam_fd;
118  
119  	if(control_host_get_debug_mode(host)==1) {
120  		int fd;
121  		char *one = "1";
122  		g_print("Enabling debug mode; not booting host\n");
123  		fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR);
124  		if (fd < 0) {
125  			g_print("ERROR HostControl: Failed to open path '%s'\n",
126  					FSI_EXTERNAL_MODE_PATH);
127  			return TRUE;
128  		}
129  		rc = write(fd, one, sizeof(*one));
130  		if (rc < 0) {
131  			g_print("ERROR HostControl: Failed to enable debug mode '%s'\n",
132  					FSI_EXTERNAL_MODE_PATH);
133  		}
134  		close(fd);
135  		return TRUE;
136  	}
137  	g_print("Booting host\n");
138  
139  	rc = fsi_rescan();
140  	if (rc < 0)
141  		return FALSE;
142  
143  	cfam_fd = open(FSI_RAW_PATH, O_RDWR);
144  	if (cfam_fd < 0) {
145  		g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH);
146  		return FALSE;
147  	}
148  
149  	control_host_complete_boot(host,invocation);
150  	do {
151  		rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000);
152  		rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000);
153  		rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF);
154  		if(rc) { break; }
155  
156  		const gchar* flash_side = control_host_get_flash_side(host);
157  		g_print("Using %s side of the bios flash\n",flash_side);
158  		if(strcmp(flash_side,"primary")==0) {
159  			rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE);
160  		} else if(strcmp(flash_side,"golden") == 0) {
161  			rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE);
162  		} else {
163  			g_print("ERROR: Invalid flash side: %s\n",flash_side);
164  			rc = 0xff;
165  
166  		}
167  		if(rc) { break; }
168  
169  		rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE);
170  	} while(0);
171  	if(rc)
172  	{
173  		g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc);
174  	}
175  	/* Close file descriptor */
176  	close(cfam_fd);
177  
178  	control_host_emit_booted(host);
179  
180  	return TRUE;
181  }
182  
183  static void
on_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)184  on_bus_acquired(GDBusConnection *connection,
185  		const gchar *name,
186  		gpointer user_data)
187  {
188  	(void) name;
189  	(void) user_data;
190  
191  	ObjectSkeleton *object;
192  	//g_print ("Acquired a message bus connection: %s\n",name);
193  	manager = g_dbus_object_manager_server_new(dbus_object_path);
194  
195  	gchar *s;
196  	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
197  	object = object_skeleton_new(s);
198  	g_free(s);
199  
200  	ControlHost* control_host = control_host_skeleton_new();
201  	object_skeleton_set_control_host(object, control_host);
202  	g_object_unref(control_host);
203  
204  	Control* control = control_skeleton_new();
205  	object_skeleton_set_control(object, control);
206  	g_object_unref(control);
207  
208  	//define method callbacks here
209  	g_signal_connect(control_host,
210  			"handle-boot",
211  			G_CALLBACK(on_boot),
212  			object); /* user_data */
213  	g_signal_connect(control,
214  			"handle-init",
215  			G_CALLBACK(on_init),
216  			NULL); /* user_data */
217  
218  	control_host_set_debug_mode(control_host,0);
219  	control_host_set_flash_side(control_host,"primary");
220  
221  	/* Export the object (@manager takes its own reference to @object) */
222  	g_dbus_object_manager_server_set_connection(manager, connection);
223  	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
224  	g_object_unref(object);
225  }
226  
227  static void
on_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)228  on_name_acquired(GDBusConnection *connection,
229  		const gchar *name,
230  		gpointer user_data)
231  {
232  	(void) connection;
233  	(void) name;
234  	(void) user_data;
235  	// g_print ("Acquired the name %s\n", name);
236  }
237  
238  static void
on_name_lost(GDBusConnection * connection,const gchar * name,gpointer user_data)239  on_name_lost(GDBusConnection *connection,
240  		const gchar *name,
241  		gpointer user_data)
242  {
243  	(void) connection;
244  	(void) name;
245  	(void) user_data;
246  	// g_print ("Lost the name %s\n", name);
247  }
248  
249  gint
main(gint argc,gchar * argv[])250  main(gint argc, gchar *argv[])
251  {
252  	GMainLoop *loop;
253  	cmdline cmd;
254  	cmd.argc = argc;
255  	cmd.argv = argv;
256  
257  	guint id;
258  	loop = g_main_loop_new(NULL, FALSE);
259  
260  	id = g_bus_own_name(DBUS_TYPE,
261  			dbus_name,
262  			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
263  			G_BUS_NAME_OWNER_FLAGS_REPLACE,
264  			on_bus_acquired,
265  			on_name_acquired,
266  			on_name_lost,
267  			&cmd,
268  			NULL);
269  
270  	g_main_loop_run(loop);
271  
272  	g_bus_unown_name(id);
273  	g_main_loop_unref(loop);
274  	return 0;
275  }
276