1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright 2022 Google LLC
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <blk.h>
8 #include <dm.h>
9 #include <fs.h>
10 #include <os.h>
11 #include <sandbox_host.h>
12 #include <asm/test.h>
13 #include <dm/device-internal.h>
14 #include <dm/test.h>
15 #include <test/test.h>
16 #include <test/ut.h>
17 
18 /* Basic test of host interface */
dm_test_host(struct unit_test_state * uts)19 static int dm_test_host(struct unit_test_state *uts)
20 {
21 	static char label[] = "test";
22 	struct udevice *dev, *part, *chk, *blk;
23 	struct host_sb_plat *plat;
24 	struct blk_desc *desc;
25 	char fname[256];
26 	ulong mem_start;
27 	loff_t actwrite;
28 
29 	ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_HOST, &dev));
30 	ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_PARTITION, &part));
31 
32 	mem_start = ut_check_delta(0);
33 	ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev));
34 
35 	/* Check that the plat data has been allocated */
36 	plat = dev_get_plat(dev);
37 	ut_asserteq_str("test", plat->label);
38 	ut_assert(label != plat->label);
39 	ut_asserteq(0, plat->fd);
40 
41 	/* Attach a file created in test_ut_dm_init */
42 	ut_assertok(os_persistent_file(fname, sizeof(fname), "2MB.ext2.img"));
43 
44 	ut_assertok(host_attach_file(dev, fname));
45 	ut_assertok(uclass_first_device_err(UCLASS_HOST, &chk));
46 	ut_asserteq_ptr(chk, dev);
47 
48 	ut_asserteq_str(fname, plat->filename);
49 	ut_assert(fname != plat->filename);
50 	ut_assert(plat->fd != 0);
51 
52 	/* Get the block device */
53 	ut_assertok(blk_get_from_parent(dev, &blk));
54 	ut_assertok(device_probe(blk));
55 
56 	/* There should be no partition table in this device */
57 	ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_PARTITION, &part));
58 
59 	/* Write to a file on the ext4 filesystem */
60 	desc = dev_get_uclass_plat(blk);
61 	ut_asserteq(true, desc->removable);
62 	ut_assertok(fs_set_blk_dev_with_part(desc, 0));
63 	ut_assertok(fs_write("/testing", 0, 0, 0x1000, &actwrite));
64 
65 	ut_assertok(host_detach_file(dev));
66 	ut_asserteq(0, plat->fd);
67 	ut_asserteq(-ENODEV, blk_get_from_parent(dev, &blk));
68 	ut_assertok(device_unbind(dev));
69 
70 	/* check there were no memory leaks */
71 	ut_asserteq(0, ut_check_delta(mem_start));
72 
73 	return 0;
74 }
75 DM_TEST(dm_test_host, UTF_SCAN_FDT);
76 
77 /* reusing the same label should work */
dm_test_host_dup(struct unit_test_state * uts)78 static int dm_test_host_dup(struct unit_test_state *uts)
79 {
80 	static char label[] = "test";
81 	struct udevice *dev, *chk;
82 	char fname[256];
83 
84 	ut_asserteq(0, uclass_id_count(UCLASS_HOST));
85 	ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev));
86 
87 	/* Attach a file created in test_ut_dm_init */
88 	ut_assertok(os_persistent_file(fname, sizeof(fname), "2MB.ext2.img"));
89 	ut_assertok(host_attach_file(dev, fname));
90 	ut_assertok(uclass_first_device_err(UCLASS_HOST, &chk));
91 	ut_asserteq_ptr(chk, dev);
92 	ut_asserteq(1, uclass_id_count(UCLASS_HOST));
93 
94 	/* Create another device with the same label (should remove old one) */
95 	ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev));
96 
97 	/* Attach a different file created in test_ut_dm_init */
98 	ut_assertok(os_persistent_file(fname, sizeof(fname), "1MB.fat32.img"));
99 	ut_assertok(host_attach_file(dev, fname));
100 
101 	ut_assertok(uclass_first_device_err(UCLASS_HOST, &chk));
102 	ut_asserteq_ptr(chk, dev);
103 
104 	/* Make sure there is still only one device */
105 	ut_asserteq(1, uclass_id_count(UCLASS_HOST));
106 
107 	return 0;
108 }
109 DM_TEST(dm_test_host_dup, UTF_SCAN_FDT);
110 
111 /* Basic test of 'host' command */
dm_test_cmd_host(struct unit_test_state * uts)112 static int dm_test_cmd_host(struct unit_test_state *uts)
113 {
114 	struct udevice *dev, *blk;
115 	struct blk_desc *desc;
116 	char fname[256];
117 
118 	/* first check 'host info' with binding */
119 	ut_assertok(run_command("host info", 0));
120 	ut_assert_nextline("dev       blocks  blksz label           path");
121 	ut_assert_console_end();
122 
123 	ut_assertok(os_persistent_file(fname, sizeof(fname), "2MB.ext2.img"));
124 	ut_assertok(run_commandf("host bind -r test2 %s", fname));
125 
126 	/* Check the -r flag worked */
127 	ut_assertok(uclass_first_device_err(UCLASS_HOST, &dev));
128 	ut_assertok(blk_get_from_parent(dev, &blk));
129 	desc = dev_get_uclass_plat(blk);
130 	ut_asserteq(true, desc->removable);
131 
132 	ut_assertok(run_command("host info", 0));
133 	ut_assert_nextline("dev       blocks  blksz label           path");
134 	ut_assert_nextlinen("  0         4096    512 test2");
135 	ut_assert_console_end();
136 
137 	ut_assertok(os_persistent_file(fname, sizeof(fname), "1MB.fat32.img"));
138 	ut_assertok(run_commandf("host bind fat %s", fname));
139 
140 	/* Check it is not removable (no '-r') */
141 	ut_assertok(uclass_next_device_err(&dev));
142 	ut_assertok(blk_get_from_parent(dev, &blk));
143 	desc = dev_get_uclass_plat(blk);
144 	ut_asserteq(false, desc->removable);
145 
146 	ut_assertok(run_command("host info", 0));
147 	ut_assert_nextline("dev       blocks  blksz label           path");
148 	ut_assert_nextlinen("  0         4096    512 test2");
149 	ut_assert_nextlinen("  1         2048    512 fat");
150 	ut_assert_console_end();
151 
152 	ut_asserteq(1, run_command("host info test", 0));
153 	ut_assert_nextline("No such device 'test'");
154 	ut_assert_console_end();
155 
156 	ut_assertok(run_command("host info fat", 0));
157 	ut_assert_nextline("dev       blocks  blksz label           path");
158 	ut_assert_nextlinen("  1         2048    512 fat");
159 	ut_assert_console_end();
160 
161 	/* check 'host dev' */
162 	ut_asserteq(1, run_command("host dev", 0));
163 	ut_assert_nextline("No current host device");
164 	ut_assert_console_end();
165 
166 	ut_asserteq(1, run_command("host dev missing", 0));
167 	ut_assert_nextline("No such device 'missing'");
168 	ut_assert_console_end();
169 
170 	ut_assertok(run_command("host dev fat", 0));
171 	ut_assert_console_end();
172 
173 	ut_assertok(run_command("host dev", 0));
174 	ut_assert_nextline("Current host device: 1: fat");
175 	ut_assert_console_end();
176 
177 	/* Try a numerical label */
178 	ut_assertok(run_command("host dev 0", 0));
179 	ut_assert_console_end();
180 
181 	ut_assertok(run_command("host dev", 0));
182 	ut_assert_nextline("Current host device: 0: test2");
183 	ut_assert_console_end();
184 
185 	/* Remove one of the bindings */
186 	ut_assertok(run_commandf("host unbind test2"));
187 
188 	/* There should now be no current device */
189 	ut_asserteq(1, run_command("host dev", 0));
190 	ut_assert_nextline("No current host device");
191 	ut_assert_console_end();
192 
193 	ut_assertok(run_command("host info", 0));
194 	ut_assert_nextline("dev       blocks  blksz label           path");
195 	ut_assert_nextlinen("  1         2048    512 fat");
196 	ut_assert_console_end();
197 
198 	return 0;
199 }
200 DM_TEST(dm_test_cmd_host, UTF_SCAN_FDT | UTF_CONSOLE);
201