Merge lp:~newell-jensen/curtin/add-arm64-support into lp:~curtin-dev/curtin/trunk

Proposed by Newell Jensen
Status: Merged
Merged at revision: 142
Proposed branch: lp:~newell-jensen/curtin/add-arm64-support
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 324 lines (+114/-30)
3 files modified
curtin/commands/block_meta.py (+69/-14)
curtin/commands/install.py (+5/-1)
helpers/common (+40/-15)
To merge this branch: bzr merge lp:~newell-jensen/curtin/add-arm64-support
Reviewer Review Type Date Requested Status
curtin developers Pending
Review via email: mp+226196@code.launchpad.net

Commit message

Add arm64 support to curtin. This branch also adds support to allow the creation of an extra /boot partition that is often times needed by arm64 boot loaders.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

What we need to consider here is that what happens in we are booting arm64/generic. Curtin will continue to see this as aarch64. This would mean that we probably won't need to do the partitioning here, as it only applies to u-boot, right?

Revision history for this message
Blake Rouse (blake-rouse) wrote :

I made some comments on the code. I know its a work in-progress. I didn't comment much on the bash code, as I do not have that much experience.

Revision history for this message
Jason Hobbs (jason-hobbs) wrote :

You can check for the '/sys/firmware/efi' directory. If it exists, then the system was booted with UEFI, not U-Boot, and doesn't require the separate boot partition. It's my understanding that arm64/generic systems booting UEFI won't require the separate /boot partition, but we would need to confirm this with the vendor. I would expect that UEFI will be able to handle either scenario - separate boot partition or not.

I have a few comments inline below too.

Revision history for this message
Scott Moser (smoser) wrote :

I'll take a look further next week,
but some nitpick comments inline.

make sure you follow the code conventions in tools/common (4 space indentation).

Revision history for this message
Newell Jensen (newell-jensen) wrote :
Download full text (16.7 KiB)

Scott,

There was a newer revision checked in last night but you commented on the
old revision. Looking over your comments. As far as tabs, I am using
emacs and it is using 4-spaces so your comment on the tab indentation seems
odd and I have checked the file and everything lines up so maybe launchpad
shows it like that? I will update branch and push so you can have a look
at it on Monday.

On Fri, Jul 18, 2014 at 6:05 AM, Scott Moser <email address hidden> wrote:

> I'll take a look further next week,
> but some nitpick comments inline.
>
> make sure you follow the code conventions in tools/common (4 space
> indentation).
>
>
> Diff comments:
>
> > === modified file 'curtin/commands/block_meta.py'
> > --- curtin/commands/block_meta.py 2014-06-19 11:51:08 +0000
> > +++ curtin/commands/block_meta.py 2014-07-15 18:09:58 +0000
> > @@ -32,7 +32,7 @@
> > 'metavar': 'DEVICE', 'default': None, }),
> > ('--fstype', {'help': 'root filesystem type',
> > 'choices': ['ext4', 'ext3'], 'default': 'ext4'}),
> > - ('mode', {'help': 'meta-mode to use', 'choices': ['raid0',
> 'simple']}),
> > + ('mode', {'help': 'meta-mode to use', 'choices': ['raid0',
> 'simple', 'simple-boot']}),
> > )
> > )
> >
> > @@ -41,6 +41,8 @@
> > # main entry point for the block-meta command.
> > if args.mode == "simple":
> > meta_simple(args)
> > + elif args.mode == "simple-boot":
> > + meta_simple_boot(args)
> > else:
> > raise NotImplementedError("mode=%s is not implemenbed" %
> args.mode)
> >
> > @@ -131,6 +133,80 @@
> > return 0
> >
> >
> > +def meta_simple_boot(args):
> > + """Similar to meta_simple but it also creates an extra /boot
> partition.
> > + This is needed from some instances of u-boot.
> > + """
> > + state = util.load_command_environment()
> > +
> > + cfg = util.load_command_config(args, state)
> > +
> > + devices = args.devices
> > + if devices is None:
> > + devices = cfg.get('block-meta', {}).get('devices', [])
> > +
> > + # Remove duplicates but maintain ordering.
> > + devices = list(OrderedDict.fromkeys(devices))
> > +
> > + if len(devices) == 0:
> > + devices = block.get_installable_blockdevs()
> > + LOG.warn("simple-boot mode, no devices given. unused list: %s",
> devices)
> > +
> > + if len(devices) > 1:
> > + if args.devices is not None:
> > + LOG.warn("simple-boot mode but multiple devices given. "
> > + "using first found")
> > + available = [f for f in devices
> > + if block.is_valid_device(f)]
> > + target = sorted(available)[0]
> > + LOG.warn("mode is 'simple-boot'. multiple devices given. using
> '%s' "
> > + "(first available)", target)
> > + else:
> > + target = devices[0]
> > +
> > + if not block.is_valid_device(target):
> > + raise Exception("target device '%s' is not a valid device" %
> target)
> > +
> > + (devname, devnode) = block.get_dev_name_entry(target)
> > +
> > + LOG.info("installing in simple-boot mode to '%s'", devname)
> > +
> > + sources = cfg.get('source...

145. By Newell Jensen

Added comments to common to help in readability and deleted some unused code.

Revision history for this message
Newell Jensen (newell-jensen) wrote :

Scott,

I am no bash expert so you might be correct that maxend might be "" but since I am setting it by doing:

        maxend=$((($size/512)-$start-$bootsize))

Won't it be something other than "" for sure?

Revision history for this message
Scott Moser (smoser) wrote :

you most certainly added tabs.

Revision history for this message
Newell Jensen (newell-jensen) wrote :

Yes, I did. Originally mis-read what you wrote. Will fix that.

On Mon, Jul 21, 2014 at 9:57 AM, Scott Moser <email address hidden> wrote:

> you most certainly added tabs.
>
> --
>
> https://code.launchpad.net/~newell-jensen/curtin/add-arm64-support/+merge/226196
> You are the owner of lp:~newell-jensen/curtin/add-arm64-support.
>

146. By Newell Jensen

Replacing tabs with spaces.

Revision history for this message
Scott Moser (smoser) wrote :

comments remaining:
 - if user specifies 'simple-boot', but is_uefi_bootable, they will get uefi. that seems possibly wrong
 - boot is passed around in helpers/common as a number. makes more sense to be a boolean, no? use 'true' or 'false' as values.
 - i dont think i like having partitioning_commands['builtin'] being dynamic.
   I think i'd rather just have 'simple' do the right thing, but let a user provided config explicitly set that.
    Also, config can be set on the command line, so:
      curtin install --set block-meta/boot-partition/enabled=True
    is the same as you have here with:
      curtin block-meta --boot

I've just proposed merging:
 bzr+ssh://bazaar.launchpad.net/~smoser/curtin/add-arm64-support/
into here. It has some cleanups. the config based approach isn't completely done there.

147. By Newell Jensen

Merging Scott Moser's changes in my branch.

148. By Newell Jensen

Added /boot partition support to UEFI.

149. By Newell Jensen

Deleted UEFI /boot partition capabilities. Stripped /boot size, sticking with
default of 512MiB. Created AUTO mode that will check for platform machine
architecture.

150. By Newell Jensen

Deleting AUTO mode to simplify things and move all the logic in block_meta.py

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'curtin/commands/block_meta.py'
2--- curtin/commands/block_meta.py 2014-07-21 17:07:39 +0000
3+++ curtin/commands/block_meta.py 2014-07-22 21:12:03 +0000
4@@ -22,24 +22,32 @@
5
6 from . import populate_one_subcmd
7
8+import os
9+import platform
10+
11+SIMPLE = 'simple'
12+SIMPLE_BOOT = 'simple-boot'
13
14 CMD_ARGUMENTS = (
15 ((('-D', '--devices'),
16 {'help': 'which devices to operate on', 'action': 'append',
17 'metavar': 'DEVICE', 'default': None, }),
18- ('--fstype', {'help': 'root filesystem type',
19+ ('--fstype', {'help': 'root partition filesystem type',
20 'choices': ['ext4', 'ext3'], 'default': 'ext4'}),
21- ('mode', {'help': 'meta-mode to use', 'choices': ['raid0', 'simple']}),
22+ ('--boot-fstype', {'help': 'boot partition filesystem type',
23+ 'choices': ['ext4', 'ext3'], 'default': None}),
24+ ('mode', {'help': 'meta-mode to use',
25+ 'choices': ['raid0', SIMPLE, SIMPLE_BOOT]}),
26 )
27 )
28
29
30 def block_meta(args):
31 # main entry point for the block-meta command.
32- if args.mode == "simple":
33+ if args.mode in (SIMPLE, SIMPLE_BOOT):
34 meta_simple(args)
35 else:
36- raise NotImplementedError("mode=%s is not implemenbed" % args.mode)
37+ raise NotImplementedError("mode=%s is not implemented" % args.mode)
38
39
40 def logtime(msg, func, *args, **kwargs):
41@@ -61,7 +69,30 @@
42 return block.get_root_device([devname, ])
43
44
45+def get_bootpt_cfg(cfg, enabled=False, fstype=None):
46+ # 'cfg' looks like:
47+ # enabled: boolean
48+ # fstype: filesystem type (default to 'fstype')
49+ # label: filesystem label (default to 'boot')
50+ # size: filesystem size in M (default to 512)
51+ # parm enable can enable, but not disable
52+ # parm fstype overrides cfg['fstype']
53+ def_boot = platform.machine() in ('aarch64')
54+ ret = {'enabled': def_boot, 'fstype': None, 'size': 512, 'label': 'boot'}
55+ ret.update(cfg)
56+ if enabled:
57+ ret['enabled'] = True
58+ if ret['enabled']:
59+ if fstype and not ret['fstype']:
60+ ret['fstype'] = fstype
61+ ret['size'] = int(ret['size'])
62+ return ret
63+
64+
65 def meta_simple(args):
66+ """Creates a root partition. If args.mode == SIMPLE_BOOT, it will also
67+ create a separate /boot partition.
68+ """
69 state = util.load_command_environment()
70
71 cfg = util.load_command_config(args, state)
72@@ -70,22 +101,27 @@
73 if devices is None:
74 devices = cfg.get('block-meta', {}).get('devices', [])
75
76+ bootpt = get_bootpt_cfg(
77+ cfg.get('block-meta', {}).get('boot-partition', {}),
78+ enabled=args.mode == SIMPLE_BOOT, fstype=args.boot_fstype)
79+
80 # Remove duplicates but maintain ordering.
81 devices = list(OrderedDict.fromkeys(devices))
82
83 if len(devices) == 0:
84 devices = block.get_installable_blockdevs()
85- LOG.warn("simple mode, no devices given. unused list: %s", devices)
86+ LOG.warn("'%s' mode, no devices given. unused list: %s",
87+ (args.mode, devices))
88
89 if len(devices) > 1:
90 if args.devices is not None:
91- LOG.warn("simple mode but multiple devices given. "
92- "using first found")
93+ LOG.warn("'%s' mode but multiple devices given. "
94+ "using first found", args.mode)
95 available = [f for f in devices
96 if block.is_valid_device(f)]
97 target = sorted(available)[0]
98- LOG.warn("mode is 'simple'. multiple devices given. using '%s' "
99- "(first available)", target)
100+ LOG.warn("mode is '%s'. multiple devices given. using '%s' "
101+ "(first available)", (args.mode, target))
102 else:
103 target = devices[0]
104
105@@ -94,10 +130,11 @@
106
107 (devname, devnode) = block.get_dev_name_entry(target)
108
109- LOG.info("installing in simple mode to '%s'", devname)
110+ LOG.info("installing in '%s' mode to '%s'", (args.mode, devname))
111
112 sources = cfg.get('sources', {})
113 dd_images = util.get_dd_images(sources)
114+
115 if len(dd_images):
116 # we have at least one dd-able image
117 # we will only take the first one
118@@ -110,19 +147,37 @@
119 logtime(
120 "partition --format uefi %s" % devnode,
121 util.subp, ("partition", "--format", "uefi", devnode))
122+ bootpt['enabled'] = False
123+ elif bootpt['enabled']:
124+ logtime("partition --boot %s" % devnode,
125+ util.subp, ("partition", "--boot", devnode))
126+ bootdev = devnode + "1"
127+ rootdev = devnode + "2"
128 else:
129 logtime(
130 "partition %s" % devnode,
131 util.subp, ("partition", devnode))
132-
133- rootdev = devnode + "1"
134-
135+ rootdev = devnode + "1"
136+
137+ # mkfs for root partition first and mount
138 cmd = ['mkfs.%s' % args.fstype, '-q', '-L', 'cloudimg-rootfs', rootdev]
139 logtime(' '.join(cmd), util.subp, cmd)
140-
141 util.subp(['mount', rootdev, state['target']])
142
143+ if bootpt['enabled']:
144+ # create 'boot' directory in state['target']
145+ boot_dir = os.path.join(state['target'], 'boot')
146+ util.subp(['mkdir', boot_dir])
147+ # mkfs for boot partition and mount
148+ cmd = ['mkfs.%s' % bootpt['fstype'],
149+ '-q', '-L', bootpt['label'], bootdev]
150+ logtime(' '.join(cmd), util.subp, cmd)
151+ util.subp(['mount', bootdev, boot_dir])
152+
153 with open(state['fstab'], "w") as fp:
154+ if bootpt['enabled']:
155+ fp.write("LABEL=%s /boot %s defaults 0 0\n" %
156+ (bootpt['label'], bootpt['fstype']))
157 fp.write("LABEL=%s / %s defaults 0 0\n" %
158 ('cloudimg-rootfs', args.fstype))
159
160
161=== modified file 'curtin/commands/install.py'
162--- curtin/commands/install.py 2014-06-08 13:52:36 +0000
163+++ curtin/commands/install.py 2014-07-22 21:12:03 +0000
164@@ -29,13 +29,15 @@
165
166 from . import populate_one_subcmd
167
168+
169 CONFIG_BUILTIN = {
170 'sources': {},
171 'stages': ['early', 'partitioning', 'network', 'extract', 'curthooks',
172 'hook', 'late'],
173 'extract_commands': {'builtin': ['curtin', 'extract']},
174 'hook_commands': {'builtin': ['curtin', 'hook']},
175- 'partitioning_commands': {'builtin': ['curtin', 'block-meta', 'simple']},
176+ 'partitioning_commands': {
177+ 'builtin': ['curtin', 'block-meta', 'simple']},
178 'curthooks_commands': {'builtin': ['curtin', 'curthooks']},
179 'late_commands': {'builtin': []},
180 'network_commands': {'builtin': ['curtin', 'net-meta', 'auto']},
181@@ -271,6 +273,8 @@
182 finally:
183 for d in ('sys', 'dev', 'proc'):
184 util.do_umount(os.path.join(workingd.target, d))
185+ if util.is_mounted(workingd.target, 'boot'):
186+ util.do_umount(os.path.join(workingd.target, 'boot'))
187 util.do_umount(workingd.target)
188 shutil.rmtree(workingd.top)
189
190
191=== modified file 'helpers/common'
192--- helpers/common 2014-04-21 16:18:39 +0000
193+++ helpers/common 2014-07-22 21:12:03 +0000
194@@ -15,6 +15,7 @@
195 -f | --format F use partition table format F. [mbr, gpt, uefi]
196 default gpt
197 -E | --end E end the partition at E (unit 1k bytes)
198+ -b | --boot create a boot partition (512 MiB - default)
199 EOF
200 [ $# -eq 0 ] || echo "$@"
201 }
202@@ -60,8 +61,8 @@
203 }
204
205 pt_gpt() {
206- local target="$1" end=${2:-""} size="" s512="" ptype="L"
207- local start="2048" pt1size="" maxend=""
208+ local target="$1" end=${2:-""} boot="$3" size="" s512="" ptype="L"
209+ local start="2048" rootsize="" bootsize="1048576" maxend=""
210 local isblk=false
211 getsize "$target" ||
212 { error "failed to get size of $target"; return 1; }
213@@ -71,15 +72,33 @@
214 else
215 end=$(($end/512))
216 fi
217- maxend=$((($size/512)-2048))
218+
219+ if [ "$boot" = true ]; then
220+ maxend=$((($size/512)-$start-$bootsize))
221+ if [ $maxend -lt 0 ]; then
222+ error "Disk is not big enough for /boot partition on $target";
223+ return 1;
224+ fi
225+ else
226+ maxend=$((($size/512)-$start))
227+ fi
228 [ "$end" -gt "$maxend" ] && end="$maxend"
229 debug 1 "maxend=$maxend end=$end size=$size"
230
231 [ -b "$target" ] && isblk=true
232
233- sgdisk --new "15:2048:+1M" --typecode=15:ef02 \
234- --new "1::$end" --typecode=1:8300 "$target" ||
235- { error "failed to gpt partition $target"; return 1; }
236+ if [ "$boot" = true ]; then
237+ # Creating 'efi', '/boot' and '/' partitions
238+ sgdisk --new "15:$start:+1M" --typecode=15:ef02 \
239+ --new "1::+512M" --typecode=1:8300 \
240+ --new "2::$end" --typecode=2:8300 "$target" ||
241+ { error "failed to gpt partition $target"; return 1; }
242+ else
243+ # Creating 'efi' and '/' partitions
244+ sgdisk --new "15:$start:+1M" --typecode=15:ef02 \
245+ --new "1::$end" --typecode=1:8300 "$target" ||
246+ { error "failed to gpt partition $target"; return 1; }
247+ fi
248
249 if $isblk; then
250 blockdev --rereadpt "$target"
251@@ -88,12 +107,16 @@
252 { error "no partition found ${target}1"; return 1; }
253 [ -b "${target}15" ] ||
254 { error "no partition found ${target}15"; return 1; }
255+ if [ "$boot" = true ]; then
256+ [ -b "${target}2" ] ||
257+ { error "no partition found ${target}2"; return 1; }
258+ fi
259 fi
260 }
261
262 pt_uefi() {
263 local target="$1" end=${2:-""} size="" s512="" ptype="L"
264- local start="2048" pt1size="" maxend=""
265+ local start="2048" rootsize="" maxend=""
266 local isblk=false
267 getsize "$target" ||
268 { error "failed to get size of $target"; return 1; }
269@@ -103,14 +126,15 @@
270 else
271 end=$(($end/512))
272 fi
273- maxend=$((($size/512)-2048))
274+
275+ maxend=$((($size/512)-$start))
276 [ "$end" -gt "$maxend" ] && end="$maxend"
277 debug 1 "maxend=$maxend end=$end size=$size"
278
279 [ -b "$target" ] && isblk=true
280
281- # Part 15 is the UEFI partition, part 1 is root
282- sgdisk --new "15:2048:+512M" --typecode=15:ef00 "$target" \
283+ # Creating 'UEFI' and '/' partitions
284+ sgdisk --new "15:2048:+512M" --typecode=15:ef00 \
285 --new "1::$end" --typecode=1:8300 "$target" ||
286 { error "failed to sgdisk for uefi to $target"; return 1; }
287
288@@ -175,22 +199,23 @@
289 }
290
291 partition_main() {
292- local short_opts="hE:f:v"
293- local long_opts="help,end:,format:,verbose"
294+ local short_opts="hE:f:bv"
295+ local long_opts="help,end:,format:,boot,verbose"
296 local getopt_out=$(getopt --name "${0##*/}" \
297 --options "${short_opts}" --long "${long_opts}" -- "$@") &&
298 eval set -- "${getopt_out}" ||
299 { partition_main_usage 1>&2; return 1; }
300
301 local cur="" next=""
302- local format="mbr" target="" end=""
303+ local format="gpt" boot=false target="" end=""
304
305 while [ $# -ne 0 ]; do
306 cur="$1"; next="$2";
307 case "$cur" in
308 -h|--help) partition_main_usage ; exit 0;;
309+ -E|--end) end=$next; shift;;
310 -f|--format) format=$next; shift;;
311- -E|--end) end=$next; shift;;
312+ -b|--boot) boot=true;;
313 -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
314 --) shift; break;;
315 esac
316@@ -222,7 +247,7 @@
317 if [ "$format" = "mbr" ]; then
318 pt_mbr "$target" "$end"
319 elif [ "$format" = "gpt" ]; then
320- pt_gpt "$target" "$end"]
321+ pt_gpt "$target" "$end" "$boot"
322 elif [ "$format" = "uefi" ]; then
323 pt_uefi "$target" "$end"
324 fi

Subscribers

People subscribed via source and target branches